Kotlin の reified キーワードはどのように機能しますか? 質問する

Kotlin の reified キーワードはどのように機能しますか? 質問する

キーワードの目的を理解しようとしていますreified。どうやら、ジェネリックのリフレクションが可能になります

ただし、これを省略しても、同様に動作します。これが実際に違いを生むのはいつでしょうか?

ベストアンサー1

TL;DR: 何reifiedに良いのか

fun <T> myGenericFun(c: Class<T>) 

のようなジェネリック関数の本体では、型はコンパイル時にのみ利用可能であるため、myGenericFun型にアクセスすることはできませんが、T消去された実行時に、ジェネリック型を関数本体で通常のクラスとして使用する場合は、に示すように、クラスをパラメータとして明示的に渡すmyGenericFun必要があります。

具体化されたinlineを持つ関数を作成すると、 の型は実行時にもアクセスできるため、 を追加で渡す必要はありません。 を通常のクラスであるかのように操作できます。たとえば、変数がのインスタンスであるかどうかを確認したい場合、次のように簡単に実行できます。 TTClass<T>T TmyVar is T

inlineを持つこのような関数は次のようになります。reifiedT

inline fun <reified T> myGenericFun()

仕組みreified

reifiedは関数と組み合わせてのみ使用できますinline。これにより、関数のバイトコードを関数が呼び出されるすべての場所にコピーするようにコンパイラに指示します (コンパイラは関数を「インライン化」します)。型inlineを使用して関数を呼び出す場合reified、コンパイラは、生成されたバイトコードを変更して対応するクラスを直接使用できるように、型引数として渡される実際の型を認識できる必要があります。したがって、 のような呼び出しは、バイトコードではmyVar is TになりますmyVar is String(型引数が の場合String)。


がいかに役立つかを示す例を見てみましょう。JSON文字列を関数のジェネリック型で指定された型のプレーンKotlinオブジェクトに変換する、calledreifiedの拡張関数を作成します。次のように使用できます。StringtoKotlinObjectTcom.fasterxml.jackson.module.kotlinこのための最初のアプローチは次のとおりです。

a) 具体化された型を使用しない最初のアプローチ

fun <T> String.toKotlinObject(): T {
      val mapper = jacksonObjectMapper()
                                                        //does not compile!
      return mapper.readValue(this, T::class.java)
}

メソッドreadValueは、 を解析するはずの型を受け取ります。型パラメータ の をJsonObject取得しようとすると、コンパイラは「'T' を具体化された型パラメータとして使用できません。代わりにクラスを使用してください。」というエラーを出力します。ClassT

b) 明示的なClassパラメータによる回避策

fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, c.java)
}

回避策として、 をClassメソッドTパラメータにして、 の引数として使用することができますreadValue。これは機能し、汎用 Java コードでは一般的なパターンです。次のように呼び出すことができます。

data class MyJsonType(val name: String)

val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)

c) Kotlin の方法:reified

型パラメータinlineを持つ関数を使用すると、関数を異なる方法で実装できるようになります。reifiedT

inline fun <reified T: Any> String.toKotlinObject(): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, T::class.java)
}

Class追加の を取る必要はなくTT通常のクラスと同じように使用できます。クライアントの場合、コードは次のようになります。

json.toKotlinObject<MyJsonType>()

重要な注意: Java の使用

reified型を持つインライン関数は、Javaコードから呼び出すことができません。

おすすめ記事