我使用本书详尽地研究了使用共方差和反方差的编译规则:http://www.cs.ucsb.edu/~benh/260/Programming-in-Scala.pdf(p 423-424)
我想出了一个不应该根据规则编译的例子,尝试过它,实际上,由于协方差/反差方法问题,它不能编译。但是,我没有看到任何合理的原因,为什么它不应该工作。因此,与Java中的Array相反,我认为,即使编译它也无法实现任何非类型安全的行为。
class TypeTest[+U] {
def call(func: () => U): U = func()
}
object Main extends App {
val test: TypeTest[Number] = new TypeTest[Integer]
test.call(() => 3)
}
编译输出是:
Main.scala:2: error: covariant type U occurs in contravariant position in type () => U of value func
def call(func: () => U): U = func()
你能告诉我这个吗?
答案 0 :(得分:3)
此定义:class TypeTest[+U]
表示,例如TypeTest[Integer]
是TypeTest[Number]
的有效替代。因此,根据Liskov substitution principle,TypeTest[Number]
可以做的任何事情,TypeTest[Integer]
也必须能够做到。但这显然不是这种情况:如果您的代码已编译,则可以向期望至少Number
的实例提供任何Integer
。
虽然一般理解这些问题可能很棘手,但您可以信任编译器的共同/逆变问题。这是因为我们很难让编译器执行这些额外的检查。但是如果你确实想要绕过差异检查,你可以做到这一点:
class TypeTest[+U] {
def call(func: Function0[U @uncheckedVariance]): U = func()
}
使用此功能的原因示例
因为这会在运行时编译并抛出:
trait Fruit
case class Orange(orangeKind: String) extends Fruit
case class Apple(appleKind: String) extends Fruit
def main(args: Array[String]) {
val testApple = new TypeTest[Apple] {
override def call(func: () => Apple) = func().copy(appleKind = "Different")
}
val testFruit: TypeTest[Fruit] = testApple
testFruit.call(() => Orange("Round"))
}