我试图理解为什么当我尝试将一个子类转换为另一个子类时,Scala运行时不会抱怨。我如何让scala抱怨。
我的应用程序中有以下继承
trait I {
val i: String
}
trait K extends I {
val k: String
}
case class S(override val i:String, override val k: String, val s: String) extends K
case class M(override val i: String, val m: String) extends I
根据我的理解,下面的方法调用应该抛出一个类强制转换异常。但它完美无缺。 listM保存了S.的列表。我能够创建MakeM的实例,使其成员包含S的List而不是M的List。这非常令人困惑。这是如何运作的? scala在将一个子类转换为另一个子类时是否聪明。当子类被转换为另一个时,我如何强制scala抱怨。
case class MakeM(val data:String, val list: Seq[M])
object Test {
def main(args: Array[String]): Unit = {
val listOfS = Some(List(S("i1", "k1", "s1"), S("i2", "k2", "s2")))
val listOfM:Seq[M] = listOfS.get.asInstanceOf[Seq[M]] //this works , why?
val m1 = MakeM("some data", listOfM); //this works. why?
//val m2 = MakeM("some data", listOfS.get); //this fails
println(s"$m1");
}
}
实际输出
MakeM(some data,List(S(i1,k1,s1), S(i2,k2,s2)))
预期输出
Class Cast exception.
答案 0 :(得分:2)
许多未编译的内容违反了类型系统。一个示例是您的代码行this fails
注释。由于类型不匹配而失败。使用asInstanceOf[]
会覆盖类型系统。
"word".asInstanceOf[Float] // this compiles, but it won't run
在你的代码中,如果你要做这样的事情......
m1.list.head.m // this compiles because you told the compiler m1 is type MakeM
...它会抛出运行时错误,因为m1
不是真的类型MakeM
。我们只是在运行时才知道,因为你告诉编译器假装不然。
这运行println(s"$m1")
(Scala代码不需要分号),因为基础toString
方法不会影响类型不一致。
听起来你希望编译器不允许不安全的转换,但是通过制作转换程序,你将取消编译器的主要安全检测器。
答案 1 :(得分:1)
我想我已经想了一下,它只检查List,而不是List [insideType]。所以它适用于List.asInstance(Seq [Anytype]),因为Seq适用于List。 但是,如果要测试内部类型级别,它将为您提供强制转换异常。
val listTemp:Seq[K] = listOfS.get.asInstanceOf[Seq[K]]
val listTemp2:Seq[Double] = listOfS.get.asInstanceOf[Seq[Double]]
println(listTemp(1)) //S(i2,k2,s2)
println(listTemp(1).k) //Exception in thread "main" java.lang.ClassCastException: S cannot be cast to K
println(listTemp2.isInstanceOf[Seq[S]]) // true, Seq[Double] is instance of Seq[S], only checks Seq
请参考这篇文章,它有一些类似的问题可能会让您感兴趣: Scala isInstanceOf and type erasure
“”“
scala> val l = List("foo")
l: List[String] = List(foo)
scala> l.isInstanceOf[List[String]]
res0: Boolean = true
scala> l.isInstanceOf[List[Int]]
<console>:9: warning: fruitless type test: a value of type List[String] cannot also be a List[Int] (the underlying of List[Int]) (but still might match its erasure)
l.isInstanceOf[List[Int]]
^
res1: Boolean = true
“”“