为什么方法和类型对方差施加不同的约束?

Why do methods and types impose different constraints on variance?

我很困惑为什么 scala 在计算方差约束时以不同的方式对待 deftype

我试图打破我的文字墙并将我的 return 类型分解为一个单独的类型声明,并立即得到一个差异错误。这是一个最小化的例子:

class Bad[+A] {
  type Check[B >: A] = Bad[B]
  def check[B >: A] : Check[B] = this
}

失败:

covariant.scala:2: error: covariant type A occurs in invariant position in type  >: A of type B
  type Check[B >: A] = Bad[B]
             ^
one error found

即使没有额外的类型声明,它仍然可以正常工作:

class Good[+A] {
  def check[B >: A]: Good[B] = this
}

class Ugly[+A] {
  type Check[B >: A @scala.annotation.unchecked.uncheckedVariance] = Ugly[B]
  def check[B >: A] : Check[B] = this
}

这是因为Check类型成员一逃到外面, 它可以立即出现在函数的协变和逆变位置 方法:

class Bad[+A] {
  type Check[B]
}

class B
class A extends B

val bad: Bad[A] = ???
import bad._

def hypotheticalMethodSomewhereOutside1(c: Check[B]) = ???
def hypotheticalMethodSomewhereOutside2(i: Int): Check[B] = ???

方法[B >: A]类型参数的关键区别check

def check[B >: A]: Good[B] = this

是单法check在你的掌握,你可以保证 它不在 not-covariant 位置使用 A

与此相反,类型成员Check可以出现在无限多的其他方法中 在共同和逆变位置,这些方法不受你的控制, 所以你不能禁止在 A 出现 not-covariant 的位置使用 Check, 例如你不能阻止 hypotheticalMethodSomewhereOutsideN 从上面的例子到 被别人定义。


请注意,方法 check 的存在对于您的 Bad 示例失败不是必需的:

// error: covariant type A occurs in invariant position in type  >: A of type B
class Bad[+A] {
  type Check[B >: A] = Bad[B]
  // def check[B >: A] : Check[B] = this
}

但是,如果您对所有人隐藏成员类型Check (实际上 每个人 ,甚至包括相同 class 的其他实例,也就是说, 使用极其隐蔽的 private[this] 访问修饰符):

class Bad[+A] {
  private[this] type Check[B >: A] = Bad[B]
}

它编译得很好。

private[this]解决了问题,因为有了这个修饰符,只有methods 必须检查 class 内部,外部某处没有假设方法 必须考虑:

class Ok[+A] {
  private[this] type Check[B >: A] = Ok[B]
  def ok[B >: A](c: Check[B]): Unit = ???
  def alsoOk[B >: A]: Check[B] = ???
}

注意上面可以写成

class Good[+A] {
  type Check[+B] = Good[B]
  def ok[B >: A](c: Check[B]): Unit = ???
  def alsoOk[B >: A]: Check[B] = ???
}

仅当类型构造函数 Good 的参数比 Check.

多得多时才有意义