[英]Scala covariant type error
I tried to define a class 我试图定义一个类
abstract class Sequence[+A] {
def append (x: Sequence[A]): Sequence[A]
}
and got in the terminal 并进入了终端
<console>:8: error: covariant type A occurs in contravariant position in type Sequence[A] of value x
def append (x: Sequence[A]): Sequence[A]
Why isn't this definition OK and what would be the best way to fix this? 为什么这个定义没有问题,解决这个问题的最佳方法是什么? I checked this covariant type T occurs in contravariant position but nothing helpful for me there.
我检查了这个协变类型T发生在逆变位置,但对我没有任何帮助。
As usual given his expertise in Scala, @vptheron is exactly right on the solution. 像往常一样,鉴于他在Scala方面的专业知识,@ vptheron完全正确的解决方案。 But let me add a little to the "why" with an example inspired by Scala author Martin Odersky himself.
但是,让我在Scala作者Martin Odersky亲自启发的示例中添加一些“为什么”。
By defining Sequence[+A]
, you're saying if B
is a subtype of A
, then Sequence[B]
is a subtype of Sequence[A]
. 通过定义
Sequence[+A]
,您说如果B
是A
的子类型,则Sequence[B]
是Sequence[A]
的子类型。
I think type stuff makes a lot more sense when you take it out of the abstract (no pun intended) and use a concrete example. 我认为类型的东西更有意义,当你把它从抽象(没有双关语意图),并使用一个具体的例子。
Let's create a concrete implementation: 让我们创建一个具体的实现:
class IntSequence extends Sequence[Int] {
override def append(x: Sequence[Int]) = {
println(math.sqrt(x.head))
//makes no sense but humor me
}
}
Covariance in A
means that because Int
is a subtype of Any
, Sequence[Int]
is a subtype of Sequence[Any]
. A
协方差意味着因为Int
是Any
的子类型,所以Sequence[Int]
是Sequence[Any]
的子类型。 So far so good. 到现在为止还挺好。
Now imagine a concrete class StringSequence
defined in a similar way to IntSequence
. 现在想象一下以与
IntSequence
类似的方式定义的具体类StringSequence
。
Then let's do this: 然后我们这样做:
val x:Sequence[Any] = new IntSequence
val ss:Sequence[Any] = new StringSequence
//Let ss be populated somehow
x.append(ss)
The first line is valid of course. 第一行当然有效。
IntSequence
is a subclass of Sequence[Int]
, and Sequence[Int]
is a subtype of Sequence[Any]
by covariance. IntSequence
是Sequence[Int]
的子类, Sequence[Int]
是协方差的Sequence[Any]
的子类型。
The second line is valid of course. 第二行当然有效。 For a similar reason.
出于类似的原因。
The third line (the line after the comment) is valid of course. 第三行(评论后的行)当然有效。
Sequence[String]
is a subclass of Sequence[Any]
, so I can append a Sequence[String]
to a Sequence[Any]
. Sequence[String]
是Sequence[Any]
的子类,因此我可以将Sequence[String]
附加到Sequence[Any]
。
But when I try the two lines together, I have now said that I can take the square root of the first element of my Sequence[String]
because x
is really a IntSequence
. 但是当我一起尝试这两行时,我现在说我可以取
Sequence[String]
的第一个元素的平方根,因为x
实际上是一个IntSequence
。
To borrow a line from the American movie Apollo 13, "Houston, we have a problem." 借用美国电影“阿波罗13号”中的一句话,“休斯顿,我们遇到了问题。”
This is why you get that error. 这就是你得到那个错误的原因。 To generalize, as soon as a generic parameter appears as the type of a parameter to a method, the class that contains that method can't be covariant in that type because you get exactly that kind of weirdness.
为了概括, 一旦泛型参数作为方法的参数类型出现,包含该方法的类在该类型中不能是协变的,因为你得到了那种奇怪的东西。
To get around this, you need a lower bound for the type parameter in the method definition. 要解决此问题,您需要方法定义中type参数的下限。 In other words, the type in the method parameter must be a supertype of the covariant type in the class definition.
换句话说,method参数中的类型必须是类定义中协变类型的超类型。
Or more simply, do what @vptheron does. 或者更简单地说,做@vptheron做的事情。
Hope that helps. 希望有所帮助。
This works: 这有效:
abstract class Sequence[+A]{
def append[B >: A](x: Sequence[B]): Sequence[B]
}
When you define a covariant type you can't use it as an input parameter (you would have the same problem with a contravariant type used for a returned type). 定义协变类型时,不能将其用作输入参数(对于返回类型使用的逆变类型,您会遇到同样的问题)。 The workaround is to define a new type (here B) that is a super type of A.
解决方法是定义一个超类型A的新类型(此处为B)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.