这段代码似乎建立了一个逆变示例: FruitBox 可以接收苹果或橙子。

class Fruit(name: String) { }
case class Apple(name: String) extends Fruit(name) {}
case class Orange(name: String) extends Fruit(name) {}

class Box[-T] {
  type U >: T
  def put(t: U): Unit= {box += t}
  val box = scala.collection.mutable.ListBuffer[U]()
}

  object test {
   val FruitBox = new Box[Fruit]
   // Fruit Box takes in everything
   FruitBox.put(new Fruit("f1"))
   FruitBox.put(new Orange("o1"))
   FruitBox.put(new Apple("a1"))

   // and Orange Box takes in only oranges
    val OrangeBox = new Box[Orange]
     //OrangeBox.put(new Apple("o2")  ==> Compile Error that makes sense
    OrangeBox.put(new Orange("o2"))

   // Contra-variant nature is also demonstrated by
     val o: Box[Orange] = FruitBox
  }

这一切都很好……但为什么它有效?具体来说:
1. FruitBox初始化时,为什么“type U >:T”没有将其约束为Fruit的父类(super class)型?尽管有这种限制, FruitBox 还是能够放置子类型 if Fruit( oranges 和 apples )......如何?

最佳答案

首先,虽然 Scala 允许您编写 new Box[Fruit] ,但将 U 保留为抽象成员,但我不明白为什么。然而,Scala 似乎在这种情况下假设 U = T。由于您的代码从未实现 U ,因此可以将其替换为 T 。所以你最终得到 def put(t: Fruit) 中的 FruitBox :当然它接受 Apple s,因为它们是 Fruit s! Scala 唯一知道 U 的是它是 T 的父类(super class)型;因此 TU 的子类型,T 的每个子类型也是如此。所以 Fruit 的任何子类型都可以传递给 FruitBox.put 。因此 def put(t: U): Unit 实际上与 put(t: T): Unit 相同,除非您像在 U 中那样实现 new Box[Fruit] { type U = Object }



这根本不是逆变行为。你会得到完全一样的

class Box[T] {
  def put(t: T): Unit= {box += t}
  val box = scala.collection.mutable.ListBuffer[T]()
}

关于scala - 为什么/这个scala逆变示例如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44233663/

10-14 13:33
查看更多