1. ホーム
  2. スカラ

[解決済み】Scalaの型消去を回避するにはどうしたらいいですか?または、なぜ私のコレクションの型パラメータを取得することができないのですか?

2022-03-24 06:03:57

質問

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

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?!

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

どうすれば解決するの?

<ブロッククオート

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

ScalaがType Erasureで定義されたのは、Java Virtual Machine(JVM)がJavaと違ってジェネリックを取得しなかったからです。これは、実行時に、クラスだけが存在し、その型パラメータは存在しないことを意味します。この例では、JVMはそれが scala.collection.immutable.List でパラメータ化されていることは知らない。 Int .

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

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リフレクションライブラリが完成すれば、より安定で強固なものになると期待している。