【发布时间】:2015-06-08 04:48:56
【问题描述】:
为什么下面的代码在Foo 不变时有效,但在协变时无效? Foo 的协变版本会产生一个类型错误,指出在调用 useF1 时,参数的类型为 Foo[T] 但需要 F1。 useF2 会产生类似的错误。
如果从Foo 中删除方差注释,则代码有效。针对F1 的模式匹配暴露了T = Int 的事实,因此x 具有Foo[Int] 类型。隐式转换函数用于将Foo[Int] 转换为F1 在useF1 的参数中。 F2 也是如此。当 Foo 是协变时,这个过程的哪一部分不同,为什么?
// A GADT with two constructors
sealed abstract class Foo[+T]
final case class F1() extends Foo[Int]
final case class F2() extends Foo[Unit]
object Example {
// A Foo[Int] can only be an F1
implicit def refineGADT(x : Foo[Int]) : F1 = x.asInstanceOf[F1]
// A Foo[Unit] can only be an F2
implicit def refineGADT(x : Foo[Unit]) : F2 = x.asInstanceOf[F2]
def useF1(x : F1) = ()
def useF2(x : F2) = ()
def demo[T](x : Foo[T]) = x match {
case F1() => useF1(x) // error
case F2() => useF2(x) // error
}
}
虽然 GADT 通常会使子类型变得更加复杂,但在这种情况下,仅有的两种可能的具体类型是 Foo[Int] 和 Foo[Unit],它们之间不存在子类型关系,因此子类型不应影响此示例。
【问题讨论】: