S-JIS[2013-06-08] 変更履歴
Javaは型消去(type erasure)という仕組みになっているので、実行時にジェネリクス(型パラメーター)の情報が消えてしまう。
ScalaもJavaVM上で動いているので、事情は同じ。
しかしScala(2.10以降)にはClassTagというトレイト(とオブジェクト)があり、これで型パラメーターの情報も受け渡せる。
(2.9以前はClassManifestを使う)
Javaで型パラメーターが必要なメソッドを作る場合は、引数でClassを渡すようなロジックにする必要があった。
ScalaでもJavaと同様にClassTagを引数で渡す必要がある。しかし暗黙の引数を利用して、明示的に記述しなくても済む。
Scala | 備考 |
---|---|
import scala.reflect.ClassTag def f[T](list: Seq[T])(implicit c: ClassTag[T]) = { println(list) println(c) } scala> f(Seq("a", "b", "c")) List(a, b, c) java.lang.String |
ClassTagを暗黙の引数にすれば、その値を明示的に指定しなくてよい。 |
def f[T: ClassTag](list: Seq[T]) = { val c = implicitly[ClassTag[T]] println(list) println(c) } scala> f(Seq("a", "b", "c")) List(a, b, c) java.lang.String |
context boundの構文を使った例。 context boundを使ったメソッド定義の結果は、普通の暗黙の引数を使ったのと同じ形になっている。 ただし変数名は自動生成されるので直接は使えない。 そこでimplicitly関数を使ってClassTagインスタンスを取得する。 |
ClassTagを使ってjava.lang.Classを取得したりインスタンスを生成したりする方法。
例 | 備考 | |
---|---|---|
Classの取得 |
class Example[T](implicit m: ClassTag[T]) { def printClass(): Unit = { val c = m.runtimeClass println(c) } } val s = new Example[String] s.printClass() |
runtimeClassでClass[_] が取れる。 |
インスタンスの生成 |
class Example[T](implicit m: ClassTag[T]) { def create(): T = { m.runtimeClass.newInstance().asInstanceOf[T] } } val s = new Example[String] val v = s.create() |
|
配列の生成 |
class Example[T](implicit m: ClassTag[T]) { def create(size:Int): Array[T] = { m.newArray(size) } } val s = new Example[Int] val a = s.create(10) |
配列の生成はClassTagに専用のメソッドがある。 |
クラス判断 |
class Example[T](implicit m: ClassTag[T]) { def check(o:AnyRef): Boolean = { (o ne null) && m.runtimeClass.isInstance(o) } } val d = new Example[java.util.Date] assert( d.check(new java.util.Date()) ) assert( d.check(new java.sql.Date(0)) ) assert(!d.check("abc") ) assert(!d.check(null) ) val q = new Example[java.sql.Date] assert( q.check(new java.sql.Date(0)) ) assert(!q.check(new java.util.Date()) ) |
Javaのinstanceof相当。 |
class Example[T](implicit m: ClassTag[T]) { def check[S](o: S)(implicit s: ClassTag[S]): Boolean = { m.runtimeClass.isAssignableFrom(s.runtimeClass) } } |
Javaのinstanceof相当。 |