scala – 为什么较低类型的边界会改变方差位置?

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问题新狗实际上会返回一个哺乳动物.这显然不是一件好事.值得庆幸的是,类型系统实际上并没有让我们这样做.

证明完毕逆变类型参数下限类型绑定不是一个好主意混合.

我希望这个例子有所帮助.

点赞