【问题标题】:Scala Generic: The return data type of a method with lower bound typeScala Generic:具有下限类型的方法的返回数据类型
【发布时间】:2018-09-07 06:12:53
【问题描述】:

我已经定义了一些 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)
}

然后我运行下面的代码sn-p:

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))在我这边可以编译成功,谁能帮忙解释一下为什么?

非常感谢!

【问题讨论】:

    标签: scala generics


    【解决方案1】:

    发生这种情况是因为下限类型、类型推断和协方差。

    colasVM 是一个 VendingMachine[Cola],所以它的类型参数 A 是 Cola。

    方法addAll有一个类型参数B是A的任何超类型。如果A是Cola,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

    【讨论】:

      猜你喜欢
      • 2018-10-19
      • 1970-01-01
      • 2020-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      相关资源
      最近更新 更多