Scala で型消去を回避するにはどうすればいいですか? または、コレクションの型パラメータを取得できないのはなぜですか? 質問する

Scala で型消去を回避するにはどうすればいいですか? または、コレクションの型パラメータを取得できないのはなぜですか? 質問する

Scala では、List[Int] をインスタンス化する場合、インスタンスが List であることは検証できますが、そのインスタンスの個々の要素が Int であることは検証できますが、List[Int] であることは簡単に検証できないという悲しい事実があります。

scala> List(1,2,3) match {
     | case l : List[String] => println("A list of strings?!")
     | case _ => println("Ok")
     | }
warning: there were unchecked warnings; re-run with -unchecked for details
A list of strings?!

-unchecked オプションは、型の消去に責任を全面的に押し付けます。

scala>  List(1,2,3) match {
     |  case l : List[String] => println("A list of strings?!")
     |  case _ => println("Ok")
     |  }
<console>:6: warning: non variable type-argument String in type pattern is unchecked since it is eliminated by erasure
        case l : List[String] => println("A list of strings?!")
                 ^
A list of strings?!

それはなぜですか? また、どうすれば回避できますか?

ベストアンサー1

この回答Manifestでは、Scala 2.10 以降では非推奨となっている -API を使用しています。最新の解決策については、以下の回答を参照してください。

Scala は、Java とは異なり、Java 仮想マシン (JVM) がジェネリックを持たないため、型消去を使用して定義されました。つまり、実行時にはクラスのみが存在し、その型パラメータは存在しません。例では、JVM は を処理していることを認識していますscala.collection.immutable.Listが、このリストが でパラメータ化されていることは認識していませんInt

幸いなことに、Scala にはそれを回避できる機能があります。それは Manifest です。Manifestは、インスタンスが型を表すオブジェクトであるクラスです。これらのインスタンスはオブジェクトなので、渡したり、保存したり、一般的にメソッドを呼び出したりすることができます。暗黙のパラメータのサポートにより、非常に強力なツールになります。たとえば、次の例を見てみましょう。

object Registry {
  import scala.reflect.Manifest
  
  private var map= Map.empty[Any,(Manifest[_], Any)] 
  
  def register[T](name: Any, item: T)(implicit m: Manifest[T]) {
    map = map.updated(name, m -> item)
  }
  
  def get[T](key:Any)(implicit m : Manifest[T]): Option[T] = {
    map get key flatMap {
      case (om, s) => if (om <:< m) Some(s.asInstanceOf[T]) else None
    }     
  }
}

scala> Registry.register("a", List(1,2,3))

scala> Registry.get[List[Int]]("a")
res6: Option[List[Int]] = Some(List(1, 2, 3))

scala> Registry.get[List[String]]("a")
res7: Option[List[String]] = None

要素を保存するときに、その「マニフェスト」も保存します。マニフェストは、インスタンスが Scala 型を表すクラスです。これらのオブジェクトには JVM よりも多くの情報が含まれており、完全なパラメータ化された型をテストできます。

ただし、 はManifestまだ進化中の機能であることに注意してください。 制限の一例として、現時点では、 は変動性について何も知らず、すべてが共変であると想定しています。 現在開発中の Scala リフレクション ライブラリが完成すれば、 はより安定して堅牢になると思います。

おすすめ記事