2017-09-12 16 views
0

以下の関数は、(型指定されていない)Java APIと特に厄介なものとインタフェースしなければならないコードの一部です。安全にコンテキストがタイプどうあるべきかを「知っている」のキャストを実行するためのものが、私は、実行時にいくつかの未知のエッジケースに悪い故障モードを持っていませんを確認するにされていますScalaコンパイラの問題またはJVMのボクシングのサブミティ?

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

詳細については、hereおよびhereを参照してください。 Scala asInstanceOfについて多くのことを説明しています。

希望すると助かります!

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

ジェネリック型Aため.asInstanceOf[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 
}