scala类型转换如何工作?

时间:2016-08-02 01:32:09

标签: scala casting classcastexception

我试图理解为什么当我尝试将一个子类转换为另一个子类时,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.

2 个答案:

答案 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

“”“