这段代码似乎建立了一个逆变示例: 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)型;因此 T
是 U
的子类型,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/