一个简单的问题。类不可变::
的方法List
定义为:
密封抽象类列表[+ A] ...
def :: [B>:A](x:B):列出[B]
假设我说:
class Fruit
class Mango extends Fruit
scala> val d:List[Fruit] = List.empty[Fruit]
d: List[Fruit] = List()
scala> new Mango :: d
res5: List[Fruit] = List(Mango@272d6774)
现在我很困惑。根据{{1}}声明,参数类型应该是逆变的。即在这种情况下::
的任何一类(我理解为什么这样做)。但我得到的是>: Fruit
,那么为什么编译器不会抛出错误?
答案 0 :(得分:5)
即使Mango
不变,您仍然可以将d
添加到List
,因为Mango
仍然是Fruit
。根据普通的旧Java列表来考虑它:
val d = new java.util.ArrayList[Fruit]
d.add(new Mango)
因此,逆变不会限制您添加子类型的能力 - 它使您能够添加超类型并从中获取编译器检查的列表类型:
val d: List[Fruit] = Nil
val a: List[Plant] = new Carrot :: d
答案 1 :(得分:3)
在第
行new Mango :: d
您希望编译器推理:“new Mango
的类型为Mango
,而d
的类型为List[Fruit]
,因此List[Fruit].::(Mango)
需要进行类型检查,而不是“T”。在这种情况下,它确实是一个错误。
但事实上,它的理由不同:“我需要new Mango :: d
进行类型检查,因此new Mango
必须某些类型B
,以便B :> Fruit
是否有这样的B
?是的,B = Fruit
。“所以没有错误。