Scala Co-Variant有界类型

时间:2015-07-06 14:01:14

标签: scala

我正在使用以下示例玩Scala的类型系统:

scala> sealed trait A
defined trait A

scala> case class A1(n: Int) extends A
defined class A1

scala> case class A2(n: Int) extends A
defined class A2

scala> case class MyCase[+P <: A](a: A, y: String)
defined class MyCase

scala> val l = List(MyCase[A1](A1(1), "A1"), MyCase[A2](A2(2), "A2"))

现在,当我执行以下操作时:

scala> l.head.asInstanceOf[MyCase[A2]]
res2: MyCase[A2] = MyCase(A1(1),A1)

如何将MyCase[A1]实例分配给MyCase[A2]引用?我的意思是MyCase[A1]MyCase[A2]在对象层次结构中处于同一级别!

1 个答案:

答案 0 :(得分:2)

据我了解,您想知道为什么在运行时没有收到错误,当您执行l.head.asInstanceOf[MyCase[A2]]时。所以答案很简单 - type erasure。对于JVM,两种类型都是相同的,因为它忽略了泛型参数 - 它只是不知道它们,因为它们仅存在于编译器级别,所以只有编译器才能给你一个例外:

scala> val mcA2: MyCase[A2] = l.head
<console>:15: error: type mismatch;
 found   : MyCase[Product with Serializable with A]
 required: MyCase[A2]
       val mcA2: MyCase[A2] = l.head
                                ^

但是,asInstanceOf会忽略此检查。所以当你这样做时

case class MyCase[+P <: A](a: P) //P instead of A
scala> val k = MyCase[A1](A1(0)).asInstanceOf[MyCase[A2]]
k: MyCase[A2] = MyCase(A1(0))

scala> val a: A2 = k.a
java.lang.ClassCastException: A1 cannot be cast to A2
... 33 elided

但是在你的例子中 - 你从未真正在运行时使用P(并且它是不可能的),所以你永远不会得到ClassCastException。实际上,在这些条件下(没有真实实例),您可以进行类型级copy like here,但使用特征更安全。