我在Scala中有以下类/特征
trait Write[-T] {
def add(elem : T);
}
class ContraListWrapper[T] (var list : List[T]) extends Write[T] {
def add(elem : T) = {
list = elem :: list
}
}
def bar(list : Write[Number]) = {}
由于Write特性的逆转,使用List of Object或Numbers列表调用该方法是有效的。
var list : List[Number] = Nil;
var wlist = new ContraListWrapper(list);
bar(wlist);
var list : List[Object] = Nil;
var wlist = new ContraListWrapper(list);
bar(wlist);
当我使用Integer列表调用bar时,我在Scala中收到编译错误。这是预期的;整数不是数字的超类型(但是子类型)
var list : List[Integer ] = new Integer(1) :: Nil;
var wlist = new ContraListWrapper(list);
bar(wlist); //error: type mismatch;
//found : contra.this.ContraListWrapper[Integer]
//required: contra.this.Write[Number]
但是当我内联一个Integer列表的变量声明时,编译错误就消失了,它甚至看起来都有效。 (我可以在方法 bar )
中添加元素到列表中var list : List[Integer] = new Integer(1) :: Nil;
bar(new ContraListWrapper(list)); //no compile- nor runtime error
编辑:以粗体
回答雷克斯克尔1)这怎么可能? 选择第一个类型Integer,内联Number
2)如果没有内联,为什么不是这种情况? Scala可以采取适当的类型
3)为什么我不会遇到运行时错误? 因为列表是协变的
聚苯乙烯。我知道如果没有特征和包装,并且有一个限制,我可以得到逆转。
答案 0 :(得分:3)
List
是协变的,因此List[Number]
是List[Integer]
的超类型。在第二种情况下,Scala查看代码然后说:“嗯,bar想要用Number输入的东西,所以让我们看看我们是否可以让ContraListWrapper
返回那个。当然我们可以 - 我们可以告诉它它正在变得越来越好List[Number]
代替List[Integer]
。“
在第一种情况下,类型已经修复。
您可以通过将第二种情况更改为
来证明这一点bar(new ContraListWrapper[Integer](list));
这会产生编译时错误,因为编译器不能自由选择类型为Number
。