我如何为协变泛型类型参数添加别名

时间:2014-10-18 00:18:13

标签: scala covariance type-alias

以下代码无法编译(在Scala 2.11中):

case class CovariantClass[+R](value: R) {
  type T = R
  def get: R = value
}

object Main {
  def main(args: Array[String]): Unit ={
    println(CovariantClass[String]("hello").get)
  }
}

错误消息是:

Error:(4, 8) covariant type R occurs in invariant position in type R of type T
  type T = R
       ^

为什么我不能为协变类型参数添加别名?如果我删除行type T = R,代码将编译并打印hello,因此别名似乎是问题所在。不幸的是,这意味着我无法为更复杂的类型创建别名,例如,type T = List[R]也不会编译,尽管List是协变的。

2 个答案:

答案 0 :(得分:5)

来自scala spec

  

类型别名的右侧始终处于不变位置。

这意味着您无法创建别名T并在右侧指定变体类型R。这同样适用于List[R],因为它也是协变的。

可以,但是提供带有类型参数的类型别名:

case class CovariantClass[+R](value: R) {
  type T[+R] = List[R]
  def get: R = value
}

如果您发现自己想要为类型参数R添加别名,那么您应该首先将其命名为其他内容。

答案 1 :(得分:4)

它是被禁止的,因为它会允许一个不正确的程序,这始终是规则。你可以像这样重写它:

case class CovariantClass[+R](value: R) {
  type T <: R
  def get: R = value
}

关于它如何破坏的一个例子,考虑一下:

case class CovariantClass[+R](value: R) {
  type T = Int
  def get: R = value
  def put(x: T) {}
  def put2(x: R) {}
}

由于T的定义方式,它是不变的。这意味着它可以用在协变类型不能的地方,如上所示。请注意put编译但put2不编译。