内联时缺少编译/运行时错误

时间:2010-09-07 13:27:45

标签: scala compiler-errors contravariance

我在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)为什么我不会遇到运行时错误? 因为列表是协变的

聚苯乙烯。我知道如果没有特征和包装,并且有一个限制,我可以得到逆转。

1 个答案:

答案 0 :(得分:3)

List是协变的,因此List[Number]List[Integer]的超类型。在第二种情况下,Scala查看代码然后说:“嗯,bar想要用Number输入的东西,所以让我们看看我们是否可以让ContraListWrapper返回那个。当然我们可以 - 我们可以告诉它它正在变得越来越好List[Number]代替List[Integer]。“

在第一种情况下,类型已经修复。

您可以通过将第二种情况更改为

来证明这一点
bar(new ContraListWrapper[Integer](list));

这会产生编译时错误,因为编译器不能自由选择类型为Number