Scala Language Specification (Section 4.5 on Variance Annotations, p. 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.
所以,我的问题如下:假设,上面的两段代码被允许,出现问题的例子是什么?这意味着,我正在寻找示例similar to this one,它说明了在上面引用的两条规则未被使用的情况下可能出现的问题.我对涉及较低类型边界的示例特别感兴趣.
请注意,Scala type bounds & variance的答案是打开这个特定问题,而The “lower bound” will reverse the variance of a type, but why?给出的答案对我来说似乎不对.
编辑:我认为第一种情况可以如下处理(适应上面引用的例子).假设,允许以下内容
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")
这显然很麻烦.但是,我看不出如何调整这个以表明组合“逆变型参数下限类型”也存在问题?
最佳答案 假设我们允许类具有类型参数[-T],并且该类的方法具有[U>:T] …
for come class hierarchy
Dog <: Mammal <: Animal
class Contra[-X](x: X){
def problem[Y >: X](y: Y): Y = x // X<:Y so this would be valid
}
val cMammal:Contra[Mammal] = new Contra(new Mammal)
val a:Animal = cMammal problem new Animal // Animal >: Mammal, this is fine
val m:Mammal = cMammal problem new Mammal // Mammal >: Mammal, this is fine
val d:Mammal = cMammal problem new Dog // (Dog upcasts to Mammal) >: Mammal, this is fine
val cDog:Contra[Dog] = cMammal // Valid assignment
val a:Animal = cDog problem new Animal // Animal >: Mammal, this is fine
val m:Mammal = cDog problem new Mammal // Mammal >: Mammal, this is fine
val d:Dog = cDog problem new Dog // AAAHHHHHHH!!!!!!
这最后一行会输入检查,cDog问题新狗实际上会返回一个哺乳动物.这显然不是一件好事.值得庆幸的是,类型系统实际上并没有让我们这样做.
证明完毕逆变类型参数下限类型绑定不是一个好主意混合.
我希望这个例子有所帮助.