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")
这显然很麻烦。但是,我看不出如何调整这个以显示组合&#34;逆变类型参数+下限类型绑定&#34;也有问题吗?
答案 0 :(得分:1)
使用++
中的List
方法查看为何需要限制。请注意,这需要++
生成List[B]
:
def ++[B](that: GenTraversableOnce[B]): List[B]
带有
的完整签名 def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
为什么[B >: A]
重要。好吧,如果我们想要结合这样的东西
trait Foo
trait Bar extends Foo
我们有一个带签名的方法
def op(that: List[Foo], other: Foo): List[Foo] = that ++ List(other)
我可以将Bar
类型的列表传递给它,但为了能够将其作为List[Foo]
返回,我必须使条件为Foo >: Bar
以便我能够实际执行以下
def see(that: List[Bar]): List[Foo] = op(that, myFoo)
基本上正在执行List[Bar] ++ List[Foo]
以返回List[Foo]
类型,如List[Foo]
类型所表示的那样。这就是翻转发生的原因。
现在,如果我试图强制执行Foo <: Bar
,我会立即遇到List[Bar] ++ List[Foo]
无法返回类型Foo
的列表的问题(更不用说它与定义冲突了)上面。)它只能返回最小上限的List
。
答案 1 :(得分:1)
假设我们允许某个类具有类型参数[-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 problem new Dog
实际上会返回Mammal
。这显然不是一件好事。值得庆幸的是,类型系统实际上并没有让我们这样做。
Q.E.D。逆变类型参数+低级类型绑定不是一个好主意混合。
我希望这个例子有所帮助。