Questo ha a che fare con il modo in cui l'inferenza di tipo/l'unificazione funziona in Scala.
Quando si definisce una variabile e lasciare fuori il tipo, Scala di applicare il tipo più specifica possibile:
scala> val v1 = Iterable(Array(123))
v1: Iterable[Array[Int]] = List(Array(123))
Tuttavia, quando si specifica il tipo previsto (ad esempio passando il valore di una funzione con una definita parametro del tipo) Scala unifica il parametro data con il tipo atteso (se possibile):
scala> val v2 : Iterable[Iterable[Any]] = Iterable(Array(123))
v2: Iterable[Iterable[Any]] = List(WrappedArray(123))
Dal Int
è un sottotipo di Any
, si verifica l'unificazione e il codice viene eseguito bene.
Se si desidera che la funzione accetti tutto ciò che è un sottotipo di Any
(senza l'aiuto di unificazione di Scala), è necessario definire questo comportamento in modo esplicito.
Edit:
Mentre quello che sto dicendo è parzialmente vero, vedere @ risposta di AlexyRomanov per una valutazione più corretta. Sembra che la "unificazione" tra Array
e Iterable
sia in realtà una conversione implicita chiamata quando si passa Iterable(Array(123))
come parametro (vedere l'effetto di ciò nella mia dichiarazione di v2
).
Supponiamo di avere un po 'di codice in cui il compilatore si aspetta il tipo B
ma trova invece il tipo A
. Prima di generare un errore, il compilatore controlla una raccolta di funzioni di conversione implicite per una con il tipo A => B
. Se il compilatore trova una conversione soddisfacente, la conversione viene applicata automaticamente (e in silenzio).
Il motivo f3
non ama v1
è perché è troppo tardi per chiamare una conversione implicita sul interna Array[Int]
e non esiste alcuna conversione implicita esistente per Iterable[Array[Int]] => Iterable[Iterable[Int]]
, anche se sarebbe banale da implementare, come mostro qui di seguito:
scala> implicit def ItAr2ItIt[T](ItAr: Iterable[Array[T]]): Iterable[Iterable[T]] = ItAr.map(_.toIterable)
ItAr2ItIt: [T](ItAr: Iterable[Array[T]])Iterable[Iterable[T]]
scala> def f3(o:Iterable[Iterable[Any]]):Unit = println("I like what I see!")
f3: (o: Iterable[Iterable[Any]])Unit
scala> val v3 = Iterable(Array(123))
v3: Iterable[Array[Int]] = List(Array(123))
scala> f3(v3)
I like what I see!
Perché "Iterable [Any]'? Questo è proprio come non usare generici/tipo affatto. – cchantep
Qualsiasi è l'interfaccia comune dell'oggetto che ho bisogno nelle mie raccolte. In alcuni contesti, Scala diventa pissy se non si specifica un tipo di parametro e invece Inferiore, in particolare quando si restituiscono i generici. – user48956
Principalmente se hai bisogno di 'Any', c'è un problema di progettazione – cchantep