Scala中的协方差

Posted

技术标签:

【中文标题】Scala中的协方差【英文标题】:Covariance in Scala 【发布时间】:2016-10-16 23:53:50 【问题描述】:

我正在学习Functional Programming Principles in Scala,在完成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 

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

List[NonEmpty] 类型的表达式不符合预期类型 列表[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]

【问题讨论】:

这应该可以编译(假设您使用的是标准 Scala List)。 NonEmptyIntSet的定义是什么? @AlexeyRomanov:我更改为 Scala List 并且它符合要求,但我不明白为什么,它们不是都是泛型类型吗? scala.collection.immutable.List[+A]A 上是协变的,由+ 符号表示。 【参考方案1】:

首先,你应该知道的是

然而,在 Scala 中,泛型类型默认具有 nonvariant(或“刚性”)子类型

covariance 表示

如果 S 是类型 T 的子类型,那么 List[S] 是否应该被视为 List[T] 的子类型

nonvariant还有另外一个意思

如果 S 是类型 T 的子类型,那么 List[S] 不应该被认为是 List[T] 的子类型

document 将为您提供帮助。只需搜索单词covariance,即可找到问题的答案。

祝你好运

【讨论】:

【参考方案2】:

问题在于您对List 的定义;它的类型参数没有前缀+,表示该类型参数是协变的。改成这样:

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

【讨论】:

以上是关于Scala中的协方差的主要内容,如果未能解决你的问题,请参考以下文章

Scala:如何获得矩阵的均值、方差和协方差?

我可以在scala中使用协方差传递不同的表单数据类型吗?

为啥方差注释会导致 Scala 无法推断出这种子类型关系?

Scala多态性 - 协变和类型绑定

方差、标准差、协方差、有啥区别?

numpy中的方差协方差相关系数