god*_*lka 5 scala generic-variance
Scala语言规范(关于方差注释的第 4.5 节,第 44 页)说
使用上面的第一点,很容易看出(至少在形式上)
trait Covariant[+A] {
def problematic[B <: A](x : B)
}
Run Code Online (Sandbox Code Playgroud)
产生错误消息
error: covariant type A occurs in contravariant position in type >: Nothing <: A of type B
def problematic[B <: A](x : B)
Run Code Online (Sandbox Code Playgroud)
使用第一点和第二点很容易看出
trait Contravariant[-A] {
def problematic[B >: A](x : B)
}
Run Code Online (Sandbox Code Playgroud)
产生错误消息
error: contravariant type A occurs in covariant position in type >: A <: Any of type B
def problematic[B >: A](x : B)
Run Code Online (Sandbox Code Playgroud)
正如我所提到的,很容易从形式上(即遵循方差注释的规则)看出这些错误发生的原因。然而,我无法举出一个例子来说明这些限制的必要性。相反,很容易举出示例来说明为什么方法参数应该更改方差位置,请参见检查方差注释。
所以,我的问题是:假设上面的两段代码是允许的,那么会出现哪些问题的例子?这意味着,我正在寻找与此类似的示例,以说明如果不使用上述两条规则,可能会出现什么问题。我对涉及下限类型的示例特别感兴趣。
请注意, Scala 类型边界和方差的答案使这个特定问题悬而未决,而“下限”中给出的答案将反转类型的方差,但为什么呢?我觉得不对。
编辑:我认为第一种情况可以按如下方式处理(改编上面引用的示例)。假设以下内容是允许的
trait Queue[+T] {
def head : T
def tail : Queue[T]
def enqueue[U <: T](x : U) : Queue[T]
}
Run Code Online (Sandbox Code Playgroud)
然后我们就可以实现
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)
}
}
Run Code Online (Sandbox Code Playgroud)
并将其用作
val x : Queue[Any] = new StrangeIntQueue
x.enqueue("abc")
Run Code Online (Sandbox Code Playgroud)
这显然很麻烦。但是,我看不出如何对此进行调整以表明“逆变类型参数+下类型界限”的组合也是有问题的?
假设我们允许一个类有一个类型参数[-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!!!!!!
Run Code Online (Sandbox Code Playgroud)
最后一行将类型检查,cDog problem new Dog实际上会返回一个Mammal. 这显然不是什么好事。值得庆幸的是,类型系统实际上并不让我们这样做。
QED 逆变类型参数 + 类型下限混合不是一个好主意。
我希望这个例子有帮助。
| 归档时间: |
|
| 查看次数: |
250 次 |
| 最近记录: |