Scala 语言规范(关于方差注释的第 4.5 节,第 44 页)说
- 类型参数的变化位置与封闭类型参数子句的变化位置相反。
- 类型声明或类型参数的下限的方差位置与类型声明或参数的方差位置相反。
使用上面的第一点,很容易(至少在形式上)看到
trait Covariant[+A] {
def problematic[B <: A](x : B)
}
产生错误信息
error: covariant type A occurs in contravariant position in type >: Nothing <: A of type B
def problematic[B <: A](x : B)
并且使用第一点和第二点很容易看出
trait Contravariant[-A] {
def problematic[B >: A](x : B)
}
产生错误信息
error: contravariant type A occurs in covariant position in type >: A <: Any of type B
def problematic[B >: A](x : B)
正如我所提到的,很容易从形式上看出(即遵循方差注释的规则)为什么会发生这些错误。但是,我想不出一个例子来说明这些限制的必要性。相比之下,很容易想出一些例子来说明为什么方法参数应该改变方差位置,参见例如Checking Variance Annotations。
所以,我的问题是:假设上面的两段代码是允许的,那么出现问题的例子是什么?这意味着,我正在寻找与此类似的示例,以说明在未使用上述两个规则的情况下可能出现的问题。我对涉及下限类型的示例特别感兴趣。
请注意,Scala type bounds & variance的答案让这个特定的问题悬而未决,而“下界”中给出的答案将反转类型的方差,但为什么呢?对我来说似乎错了。
编辑:我认为第一种情况可以按如下方式处理(改编上面引用的示例)。假设,以下是允许的
trait Queue[+T] {
def head : T
def tail : Queue[T]
def enqueue[U <: T](x : U) : Queue[T]
}
然后我们可以实现
class QueueImplementation[+T] extends Queue[T] {
/* ... implement Queue here ... */
}
class StrangeIntQueue extends QueueImplementation[Int] {
override def enqueue[U <: Int](x : U) : Queue[Int] = {
println(math.sqrt(x))
super.enqueue(x)
}
}
并将其用作
val x : Queue[Any] = new StrangeIntQueue
x.enqueue("abc")
这显然很麻烦。但是,我看不出如何调整它以表明“逆变类型参数+下类型界限”的组合也有问题?