Scala编译问题还是JVM的拳击子语?

时间:2017-09-12 13:38:41

标签: scala jvm boxing

以下函数是一些代码的一部分,我必须与一个特别讨厌的(如无类型的)Java API进行交互。它旨在安全地执行强制转换,其中上下文“知道”应该的类型,但我想确保在运行时某些未知边缘情况下我不会有错误的故障模式:

def safeCast[A](o: Any): Option[A] =
  Try(o.asInstanceOf[A]).toOption

现在看看在REPL会话中使用它会发生什么:

scala> val testDouble: Double = 1.0

testDouble: Double = 1.0

scala> safeCast[Int](testDouble)

res0: Option[Int] = Some(1.0)

res0声称其类型为Option[Int],但值为Some(1.0)(即 - Some[Double])。如果我们尝试映射此选项,则会出现类强制转换异常。

此行为仅在多态safeCast时发生。如果我们收紧特定类型:

def safeIntCast(o: Any): Option[Int] = Try(o.asInstanceOf[Int]).toOption
然后我们得到:

scala> safeIntCast(testDouble)

res1: Option[Int] = None

因此,多态性以某种方式与拳击(我怀疑??)或编译器问题(bug ??)进行交互。使用的编译器版本是2.12.2

有人可以为此提供解释吗?

3 个答案:

答案 0 :(得分:2)

这是因为类型擦除,类型T在运行时是未知的。当您映射类型已知时(因为它已被评估)并且您正在获取ClassCastException。

但是你可以使用class标签在运行时获取类型:

import scala.reflect.ClassTag
import scala.util.Try

object Application extends App {

  def safeCast[A](o: Any)(implicit ct: ClassTag[A]): Option[A] =
    Try(ct.runtimeClass.cast(o).asInstanceOf[A]).toOption

}

答案 1 :(得分:1)

请参阅herehere以获取进一步的参考。它解释了很多关于Scala asInstanceOf。

希望它有所帮助!

答案 2 :(得分:0)

对于泛型类型.asInstanceOf[A],没有A这样的东西,它只是在运行时消失了:

$ echo 'class Demo { def safeCast[A](o: Any) = o.asInstanceOf[A] }' > test.scala
$ scalac test.scala
$ cfr test.scala
$ javap -c Demo
Compiled from "test.scala"
public class Demo {
  public <A> A safeCast(java.lang.Object);
    Code:
       0: aload_1
       1: areturn

  public Demo();
    Code:
       0: aload_0
       1: invokespecial #18                 // Method java/lang/Object."<init>":()V
       4: return
}