Scala 中的协方差

Covariance in Scala

我正在学习 Functional Programming Principles in Scala, as I went through the lecture Subtyping and Generics,我对协方差感到困惑:

给定:NonEmpty <: IntSetNonEmptyIntSet

的子类型

List[NonEmpty] <: List[IntSet]List[NonEmpty]List[IntSet] ?

答案是有道理的,因为非空集列表是任意集列表的特例。

这个答案是否暗示 List[NonEmpty]List[IntSet] 的子类型?

所以我尝试了这个:

val nonEmpty: List[NonEmpty] = null
val intSet: List[IntSet] = nonEmpty 

然后我得到一个编译错误:

Expression of type List[NonEmpty] doesn't conform to expected type List[IntSet]

据我所知,泛型在 Java 中是不变的,泛型在 Scala 中是协变的吗 或者我对协方差有错误的理解?

编辑:

这里是IntSet, NonEmpty, List的定义:

abstract class IntSet {
  def contains(x: Int): Boolean
  def incl(x: Int): IntSet
  def union(other: IntSet): IntSet
}

class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {...}

trait List[T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}

首先,你应该知道的是

In Scala, however, generic types have by default nonvariant (or, "rigid") subtyping

covariance 表示

if S is a subtype of type T, then should List[S] be considered a subtype of List[T]

nonvariant还有一个意思就是

if S is a subtype of type T, then should List[S] not be considered a subtype of List[T]

document 会帮助你。只需搜索 covariance 这个词,您就会找到问题的答案。

祝你好运

问题出在你对List的定义上;它的类型参数没有前缀 + 来表示类型参数是协变的。改成这样:

trait List[+T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}