2017-09-12 66 views
0

下面的函数是的一些代码我有一个特别令人讨厌的接口(如在无类型)的Java API的一部分。其目的是在上下文“知道”是什么类型应该是安全地进行类型转换,但我想确保我不会有一些未知的边缘情况不好的故障模式在运行时:斯卡拉编译器问题或JVM拳击subtlty?

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 

因此,多态性某种方式与拳击(我怀疑?)交互或编译器问题(错误? )。所使用的编译器版本为2.12.2

任何人都可以为此提供解释?

回答

1

请参阅herehere以备将来参考。它解释了很多关于Scala asInstance的内容。

希望它有帮助!

2

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

但是你可以使用类标签在运行时得到类型:

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 

} 
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 
}