我已经定义了一些Scala类:
class Drink
class SoftDrink extends Drink
class Cola extends SoftDrink
class VendingMachine[A](val currentItem: Option[A], items: List[A]) {
def this(items: List[A]) = this(None, items)
def addAll[B >: A](newItems: List[B]): VendingMachine[B] =
new VendingMachine(items ++ newItems)
}
然后我运行了以下代码段:
val colasVM: VendingMachine[Cola] = new VendingMachine(List(new Cola, new Cola))
// It works
val softDrinksVM: VendingMachine[Drink] = colasVM.addAll(List(new SoftDrink))
// Compile Error: You may wish to define A as +A instead. (SLS 4.5)
val softDrinksVM2: VendingMachine[Drink] = new VendingMachine[SoftDrink](None, null)
我认为colasVM.addAll(List(new SoftDrink))
返回VendingMachine[SoftDrink]
类型的数据,由于它们不是同一类型,因此无法将其分配给VendingMachine[Drink]
变量。
但是val softDrinksVM: VendingMachine[Drink] = colasVM.addAll(List(new SoftDrink))
可以在我这边成功编译,有人可以帮忙解释一下原因吗?
非常感谢!
答案 0 :(得分:1)
发生这种情况的原因是下界类型,类型推断和协方差。
colasVM是VendingMachine [Cola],因此其类型参数A是Cola。
方法addAll的类型参数B是A的任何超类型。如果A是可乐,则B可以是Cola,SoftDrink,Drink,甚至可以是AnyRef或Any。
当您调用addAll时,您并没有告诉编译器哪种类型是B,因此它必须进行推断。如果softDrinksVM2的类型为VendingMachine [Drink],则B必须为Drink。
为什么您的代码可以编译?因为List是协变的,所以List [SoftDrink]是List [Drink]。
如您所见,甚至可以做这样的事情。
val softDrinksVM1: VendingMachine[AnyRef] = colasVM.addAll(List(new Object))
val softDrinksVM2: VendingMachine[AnyRef] = colasVM.addAll(List(new SoftDrink))
查看此链接以获取更多信息 https://docs.scala-lang.org/tour/variances.html