2016年2月10日

Kotlin ジェネリクス 型引数の情報を実行時に取得

Kotlin 正式版がそろそろリリースされそうなので・・・
GitHub - temp-impl/spring-mvc-singleton-vs-prototype_kotlin を作った時の調査メモ。)

Kotlin も JVM 言語なので、コンパイル時型消去の呪いからは逃れられない。
が、inline と reified を使うことで、関数・メソッドなら型引数の情報を実行時に使用可能になる。

[型引数使用サンプル]

fun main(args: Array<String>) {
    printType<String>()
}

inline fun <reified T> printType() {
    println(T::class)
}

//[結果]
// class kotlin.String

//[補足]
// 上記結果を得るためには kotlin-refrect.jar も必要
// 無くてもエラー無しで実行できるが、下記結果になる
// class java.lang.String (Kotlin reflection is not available)
[上記のバイトコード(一部)]

   L2
    LINENUMBER 8 L2
    LDC Ljava/lang/String;.class
    INVOKESTATIC kotlin/jvm/internal/Reflection.getOrCreateKotlinClass (Ljava/lang/Class;)Lkotlin/reflect/KClass;
    ASTORE 1
    NOP
   L3
    LINENUMBER 11 L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V

inline というキーワードから想像が付くと思うが、関数の中身がインライン展開されている。
そのため、型引数の情報も当然使用可能。

ちなみに Java クラスの情報が欲しい場合

inline fun <reified T : Any> printJavaType() {
    println(T::class.java)
}

//[結果] (上と同じ main)
// class java.lang.String

//[補足]
// 型引数のデフォルト上限は Any? で Java に無いクラスなので、Any 上限を指定する必要がある
// .java は KClass<T : Any> の拡張プロパティ

検証環境

  • jdk 1.8.0_74
  • Kotlin 1.0.0-rc-1036

雑記

inline 関数の型引数はデフォルト reified でも良さそうと思ったが、たぶん Kotlin は(型引数使用を)明示していくスタイルなのだろう。
(コンパイラの都合もあるかもしれない・・・)

Scala の implicit + ClassTag みたいな仕組みはおそらく導入されない。
Comparison to Scala - Kotlin Programming Language を読むと implicit は導入する気が無さそうなので。

0 件のコメント:

コメントを投稿