参考
http://www.ne.jp/asahi/hishidama/home/tech/scala/r...
http://www.ne.jp/asahi/hishidama/home/tech/scala/g...
http://www.ne.jp/asahi/hishidama/home/tech/scala/r...
http://www.ne.jp/asahi/hishidama/home/tech/scala/g...
// JavaVM はコンパイルすると型情報が消えてします(type erasure) // しかし scala には型情報を渡す仕組みが用意されています。 // Predef で定義されている classManifest メソッドを使うと型情報を取得できる。 val int = classManifest[Int] println(int) println(int.getClass) // ClassManifest.erasure メソッドで java.lang.Class を取得できる println("---------") println(int.erasure) println(int.erasure.getClass) println("---------") // java.lang.Class.newInstance を使えばインスタンス生成が出来る。 val anyRef = classManifest[AnyRef].erasure // newInstance は Any を返すので asInstanceOf でキャストしなければならない // val a: AnyRef = anyRef.newInstance <= error val a: AnyRef = anyRef.newInstance.asInstanceOf[AnyRef] println(a) // インタープリタだと独自のクラスでは newInstance でエラーが出る。 // REPLやコンパイルなら上手く動く。多分パッケージ名が解決できないっぽい。 class C // classManifest[C].erasure.newInstance <= java.lang.InstantiationException // 引数のあるコンストラクタがある場合は java.lang.Class.getConstructor(s).newInstance(args) を使用する。 val str: String = classManifest[String].erasure.getConstructor(classOf[String]).newInstance("aiueo").asInstanceOf[String] println(str) // ここらへんは完全に java の領域っぽい。Int の引数のクラスも Integer じゃないと駄目らしい // 独自クラスはインタープリタでは動かないので REPL などで試してください。 //class C2(val id: Int) //classManifest[C2].erasure.getConstructor(classOf[Int]).newInstance(new Integer(10)).asInstanceOf[C2]
Int class scala.reflect.Manifest$$anon$4 --------- int class java.lang.Class --------- java.lang.Object@2c79809 aiueo
// コンパイルすると型情報は消えるので isInstanceOf[T] だと全て true になってしまう(Warning も出る) def check[T](o: AnyRef) { println(o.isInstanceOf[T]) } check[String](new AnyRef) check[String](List(1, 2, 3)) check[String]("") println("---------") // ClassManifest.erasure で取得した java.lang.Class.isInstance を使用すると型のチェックが出来る。 def check2[T](o: Any, cm: ClassManifest[T]) { println(cm.erasure.isInstance(o)) } check2[String]("", classManifest[String]) check2[String](5, classManifest[String]) check2[String](List(), classManifest[String]) println("---------") // java.lang.Class 同士をチェックする場合は java.lang.Class.isAssignableFrom を使用する val m1 = classManifest[String] val m2 = classManifest[Int] println(m1.erasure.isAssignableFrom(m1.erasure)) println(m1.erasure.isAssignableFrom(m2.erasure))
warning: there were 1 unchecked warnings; re-run with -unchecked for details one warning found true true true --------- true false false --------- true false
// 毎回 ClassManifest を引数などに指定するのはウルトラアホらしい。 // implicit を使用すれば大幅に省略できる class C[T](implicit val cm: ClassManifest[T]) // 自動的に cm = classManifest[String] をしてくれる val o = new C[String] println(o.cm) def func[T](list: List[T])(implicit cm: ClassManifest[T]) { println(list) println(cm) } func(List(1, 2, 3)) // scala2.8 から導入された「context bound」を使うと // class C[T](implicit a: A[T]) は class C[T: A] と省略することが出来る。 class C2[T: ClassManifest] { // 変数は自動生成されているので取得したい場合は implicitly を使う val cm = implicitly[ClassManifest[T]] println(cm) } new C2[List[Int]]
java.lang.String List(1, 2, 3) Int scala.collection.immutable.List[Int]
参考
http://d.hatena.ne.jp/yuroyoro/20100914/1284471301
scala 2.9.1 の時点では <%< は非推奨で => を使用する。
http://d.hatena.ne.jp/yuroyoro/20100914/1284471301
scala 2.9.1 の時点では <%< は非推奨で => を使用する。
object Main { // A から B に暗黙の型変換して欲しい場合は [A <% B] とする。これを view bound と呼ぶ // Int, Float などはそれぞれコンパイル時に RichInt, RichFloat に暗黙の型変換され、そしてその共通のスーパークラスとして ScalaNumberProxy がある。 // そしてそこに < や > などの関数が定義されている。 // なので、数値全般に共通した処理を行ないたい場合は [T <% scala.runtime.ScalaNumberProxy[T]] とすれば良い def rangeOfNumber[T <% scala.runtime.ScalaNumberProxy[T]](v: T, min: T, max: T): T = { // < や > は ScalaNumberProxy に定義されている関数である。 if ( v.<(min) ) min else if (v > max) max else v } // scala.runtime.ScalaNumberProxy はサポート外というご指摘を受けたので追記修正しました。 // Ordering を取得して比較するのが正しいお作法のようです。 rangeOfNumber と動作はほぼ一緒です。 // 一応 View Bound のサンプルとして、rangeOfNumber も置いておきますが、バージョンが変わると動かなくなるかもしれません。 def rangeOfNumber2[T: Ordering](v: T, min: T, max: T): T = { val ord = implicitly[Ordering[T]] if (ord.lt(v, min)) min else if (ord.gt(v, max)) max else v } val rangeOfInt = rangeOfNumber(_: Int, 5, 10) val rangeOfFloat = rangeOfNumber(_: Float, 20.0f, 100.0f) def p(v: Any) = println(v) def main(args: Array[String]) { // Symbol は ScalaNumberProxy に暗黙型変換できないのでコンパイル時にエラーが出る!! => type safe :) // rangeOfNumber('a, 'b, 'c) <= No implicit view available from Symbol => scala.runtime.ScalaNumberProxy[Symbol]. p(rangeOfInt(3)) p(rangeOfInt(100)) p(rangeOfInt(8)) p("-------------") p(rangeOfFloat(10.0f)) p(rangeOfFloat(50.0f)) p(rangeOfFloat(300.0f)) } }
5 10 8 ------------- 20.0 50.0 100.0
最新コメント