1. ホーム
  2. generics

[解決済み】Kotlinのreifiedキーワードはどのように機能するのですか?

2022-04-01 06:36:22

質問

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

しかし、それを省くと、同じようにうまく動作するのです。どなたか、どのような場合に実際の ?

解決方法は?

TL;DR: What is reified に良い

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

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

を作成した場合 inline 関数に リファイド T のタイプは T は実行時にもアクセスできるため、実行時に Class<T> を追加しました。を使うことができます。 T を通常のクラスと同じように扱うことができます。 のインスタンスです。 T であれば、簡単にできます。 myVar is T .

このような inline という関数があります。 reified タイプ T は次のようになります。

inline fun <reified T> myGenericFun()


どのように reified 作品

のみを使用することができます。 reified との組み合わせで inline 関数を使用します。こうすることで、コンパイラは関数のバイトコードをその関数が呼び出されたすべての場所にコピーするように指示します(コンパイラは関数を "inlines"するのです)。を呼び出すと inline 関数を reified 型の引数として渡された実際の型をコンパイラが知ることができ、生成されたバイトコードを修正して対応するクラスを直接使用できるようにしなければなりません。したがって、以下のような呼び出しは myVar is T は次のようになります。 myVar is String をバイトコードで指定します(type 引数が String ).


使用例

では、どのように役立つかを示す例を見てみましょう。 reified を使用することができます。 の拡張機能を作りたいと思います。 String という toKotlinObject この関数は、JSON 文字列を、この関数の汎用型である T . 私たちは com.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 に変換します。もし私たちが Class 型パラメタの T の場合、コンパイラは文句を言う。 "再定義された型パラメータとして 'T' を使用することはできません。代わりにクラスを使用してください。

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

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

回避策として ClassT をメソッドのパラメータにし、それを引数として readValue . これは、一般的なJavaコードでよく見られるパターンです。次のように呼び出すことができます。

data class MyJsonType(val name: String)

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

c) Kotlinの方法。 reified

を使用することで inline 関数と reified 型パラメータ T を使用すると、関数を別の方法で実装することが可能になります。

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

を取る必要はありません。 ClassT を追加しました。 T は、普通のクラスのように使うことができます。クライアント側では、このようなコードになります。

json.toKotlinObject<MyJsonType>()

重要なお知らせ:Javaでの作業について

を持つインライン関数は reified 型は Javaから呼び出すことができない のコードに置き換えられます。