为什么方法和类型对方差施加不同的约束?
Why do methods and types impose different constraints on variance?
我很困惑为什么 scala 在计算方差约束时以不同的方式对待 def
和 type
?
我试图打破我的文字墙并将我的 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
.
多得多时才有意义
我很困惑为什么 scala 在计算方差约束时以不同的方式对待 def
和 type
?
我试图打破我的文字墙并将我的 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
.