我很困惑为什么scala在计算方差约束时会以不同的方式处理def
和type
?
我试图打破我的文本墙并将我的返回类型分解为单独的类型声明,并立即得到方差错误。这是一个最小化的例子:
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
}
答案 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
时才有意义。