Scala协变类型错误

时间:2013-12-17 05:37:34

标签: scala

我试图定义一个类

abstract class Sequence[+A] {
    def append (x: Sequence[A]): Sequence[A]
}

并进入终端

<console>:8: error: covariant type A occurs in contravariant position in type Sequence[A] of value x
           def append (x: Sequence[A]): Sequence[A]

为什么这个定义不正确,解决这个问题的最佳方法是什么? 我检查了这个covariant type T occurs in contravariant position,但对我没有任何帮助。

2 个答案:

答案 0 :(得分:6)

由于他在Scala的专业知识,@ vptheron完全正确的解决方案。但是,让我在Scala作者Martin Odersky本人的启发下添加一些“为什么”的例子。

通过定义Sequence[+A],您说BA的子类型,那么Sequence[B]Sequence[A]的子类型。

我认为类型的东西在你把它从抽象中拿出来时更有意义(没有双关语意)并使用一个具体的例子。

让我们创建一个具体的实现:

class IntSequence extends Sequence[Int] {
  override def append(x: Sequence[Int]) = {
    println(math.sqrt(x.head))
    //makes no sense but humor me
  }
}

A中的协方差表示由于IntAny的子类型,Sequence[Int]Sequence[Any]的子类型。到目前为止一切都很好。

现在假设一个具体的类StringSequence以与IntSequence类似的方式定义。

然后让我们这样做:

val x:Sequence[Any] = new IntSequence
val ss:Sequence[Any] = new StringSequence
//Let ss be populated somehow
x.append(ss)

第一行当然有效。 IntSequenceSequence[Int]的子类,Sequence[Int]是协方差Sequence[Any]的子类型。

第二行当然有效。出于类似的原因。

第三行(评论后的行)当然有效。 Sequence[String]Sequence[Any]的子类,因此我可以将Sequence[String]附加到Sequence[Any]

但是当我一起尝试这两行时,我现在说我可以取Sequence[String]的第一个元素的平方根,因为x实际上是IntSequence

借用美国电影“阿波罗13号”中的一句话,“休斯顿,我们遇到了问题。”

这就是您收到该错误的原因。为了概括,一旦泛型参数作为方法的参数类型出现,包含该方法的类就不能在该类型中协变,因为你会得到那种奇怪的东西。

要解决此问题,您需要在方法定义中为type参数设置下限。换句话说,method参数中的类型必须是类定义中协变类型的超类型。

或者更简单地说,做@vptheron做的事。

希望有所帮助。

答案 1 :(得分:5)

这有效:

abstract class Sequence[+A]{
  def append[B >: A](x: Sequence[B]): Sequence[B]
}

定义协变类型时,不能将其用作输入参数(对于返回类型使用的逆变类型,您会遇到同样的问题)。解决方法是定义一个新类型(此处为B),它是A的超类型。