我正在使用以下示例玩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]
在对象层次结构中处于同一级别!
答案 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,但使用特征更安全。