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

时间:2018-03-03 18:36:36

标签: scala covariance

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

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

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
}

1 个答案:

答案 0 :(得分:2)

这是因为只要类型成员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 在您的控制之下,您可以保证 它不会在非协变位置使用A

与此相反,类型成员Check可以出现在无限多种其他方法中 在共同和逆变的位置,那些方法不在你的控制之下, 因此,您无法禁止在Check出现不协变的位置使用A, 例如您无法阻止上述示例中的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 (真的每个人,甚至包括同一类的其他实例,也就是说, 使用非常隐遁的private[this]访问修饰符):

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

它很好地编译。

private[this]解决了问题,因为使用此修饰符时,只有方法 在课堂内必须进行检查,在外面某处没有假设的方法 必须考虑到:

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时才有意义。