Scala中的协方差
Posted
技术标签:
【中文标题】Scala中的协方差【英文标题】:Covariance in Scala 【发布时间】:2016-10-16 23:53:50 【问题描述】:我正在学习Functional Programming Principles in Scala,在完成Subtyping and Generics 的讲座时,我对协方差感到困惑:
给定:NonEmpty <: IntSet
或 NonEmpty
是 IntSet
的子类型
是 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]
【问题讨论】:
这应该可以编译(假设您使用的是标准 ScalaList
)。 NonEmpty
和IntSet
的定义是什么?
@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中的协方差的主要内容,如果未能解决你的问题,请参考以下文章