在以下示例中,f3可以采用Iterable [Array [Int]]
def f3(o:Iterable[Iterable[Any]]):Unit = {}
f3(Iterable(Array(123))) // OK. Takes Iterable[Array[Int]]
但如果我将Iterable [Array [Int]]赋值给局部变量,则不能:
val v3 = Iterable(Array(123))
f3(v3) // Fails to take Takes Iterable[Array[Int]]
错误:
Error:(918, 10) type mismatch;
found : Iterable[Array[Int]]
required: Iterable[Iterable[Any]]
f3(x)
什么是软糖?为什么第一个例子工作,但不是秒。它似乎与嵌套泛型有关:
def f(o:Iterable[Any]):Unit = {}
f( Array(123))
val v1 = Array(123)
f(v1) // OK
def f2(o:Iterable[Any]):Unit = {}
f2( Iterable(Array(123)))
val v2 = Array(123)
f(v2) // OK
使用scala.2.11
答案 0 :(得分:6)
首先,Array
不会扩展Iterable
(因为它是Java类型)非常重要。相反,存在从Array[A]
到Iterable[A]
的隐式转换,因此期望的类型很重要。
在第一种情况下:Iterable(Array(123))
是f3
的参数,因此使用预期类型Iterable[Iterable[Any]]
进行类型检查。因此Array(123)
是预期类型Iterable[Any]
的类型。好吧,它的实际类型是Array[Int]
,编译器会插入转换(因为Iterable[Int]
符合Iterable[Any]
)。所以这实际上是Iterable(array2iterable(Array(123))
(我不记得确切的名字)。
在第二种情况下,f3
的类型为Iterable[Array[Int]]
:没有任何内容可以在val f3 = ...
行中触发隐式转换,对吧?当存在从Iterable[Array[Int]]
到{{的隐式转换时,从Iterable[Iterable[Int]]
到Iterable[A]
(或者更常见的是从Iterable[B]
到A
的隐式转换没有1}}),所以下一行无法编译。您可以自己编写此转换,但它不会有帮助,例如将B
转换为Array[Array[Int]]
。
当然,如果您使用Iterable[Iterable[Int]]
,则无法触发隐式转换!
答案 1 :(得分:4)
这与Scala中类型推断/统一的工作方式有关。
当您定义变量并省略类型时,Scala会应用尽可能最具体的类型:
scala> val v1 = Iterable(Array(123))
v1: Iterable[Array[Int]] = List(Array(123))
但是,当您指定期望的类型时(例如,通过将值传递给具有已定义参数类型的函数),Scala会将给定参数与预期类型(如果可能)统一起来:
scala> val v2 : Iterable[Iterable[Any]] = Iterable(Array(123))
v2: Iterable[Iterable[Any]] = List(WrappedArray(123))
由于Int
是Any
的子类型,因此会发生统一并且代码运行正常。
如果您希望函数接受Any
子类型的任何内容(没有Scala的统一帮助),则必须明确定义此行为。
修改强>
虽然我所说的部分属实,但请参阅@ AlexyRomanov的回答以获得更正确的评估。似乎"统一"在Array
和Iterable
之间实际上是一个隐式转换,当您将Iterable(Array(123))
作为参数传递时(参见我在v2
声明中的效果)。
假设您有一些代码,其中编译器期望类型B
但是找到类型A
。在抛出错误之前,编译器会检查类型为A => B
的隐式转换函数的集合。如果编译器找到了令人满意的转换,则会自动(并静默)应用转换。
f3
不喜欢v1
的原因是因为在内部Array[Int]
上调用隐式转换为时已晚,并且{{1}不存在现有的隐式转换虽然实现起来很简单,但如下所示:
Iterable[Array[Int]] => Iterable[Iterable[Int]]