1

我在 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 trait 的逆变性,使用对象列表或数字列表调用方法是可行的。

var list : List[Number] = Nil;
var wlist = new ContraListWrapper(list);
bar(wlist);

var list : List[Object] = Nil;
var wlist = new ContraListWrapper(list);
bar(wlist);

当我使用整数列表调用 bar 时,我在 Scala 中收到编译错误。这是意料之中的;整数不是 Number 的超类型(而是子类型)

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 列表的变量声明时,编译错误消失了,它甚至似乎工作。(我可以将元素添加到方法栏中的列表中)

var list : List[Integer] = new Integer(1) :: Nil;
bar(new ContraListWrapper(list)); //no compile- nor runtime error 

编辑:以粗体回答 Rex Kerr

1)这怎么可能?选择第一个类型 Integer,内联 Number

2)为什么没有内联就不是这种情况?Scala 可以采用适当的类型

3) 为什么我不会得到运行时错误?因为列表是协变的

附言。我知道我可以在没有特征和包装的情况下获得逆变,并且有界限。

4

1 回答 1

3

List是协变的,因此List[Number]是 的超类型List[Integer]。在第二种情况下,Scala 查看代码然后说:“嗯,bar 想要用 Number 输入的东西,所以让我们看看我们是否可以ContraListWrapper返回它。当然可以——我们可以告诉它它得到的是 aList[Number]而不是 a List[Integer]。 "

在第一种情况下,类型已经固定。

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

bar(new ContraListWrapper[Integer](list));

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

于 2010-09-07T14:24:10.600 回答