Kotlinでは、ジェネリック(ジェネリックパラメータ)はデフォルトで型消去(type erasure)されます:実行時には型に関する情報がありません。これにより、リフレクション、型変換、および型に関するアノテーションの読み取りが難しくなります。ほとんどのケースではこれは許容されます—通常のジェネリックはJavaと同様に機能します。
インライン関数のreifiedパラメータを使用すると、コンパイラに特定の型を呼び出し地点に「挿入」させることができるため、関数は実行時に型に対して操作を実行できます(例えば、チェックを行ったり、リフレクションを使用して新しいインスタンスを作成したりすることができます)。しかし、reifiedはinline関数のパラメータにのみ適用可能です。
比較の例:
// 通常のジェネリック fun <T> printType(t: T) { println(t.javaClass) // List<Int>などでClassCastExceptionを引き起こします。 } // reifiedを使用した場合 inline fun <reified T> printType(t: T) { println(T::class.simpleName) } fun main() { printType(123) // 出力:Int printType("hello") // 出力:String }
適用の実践: 最も一般的に、型のチェック、キャスティング、リフレクション、インスタンスの作成に使用され、他の方法では型を取得できません。
「reified型の関数はインラインでないと動作しますか?」
reifiedはインライン関数でのみ機能します。そうでなければ、コンパイル時に型の挿入が不可能になります。誤った使用例:
fun <reified T> failFunction() {} // コンパイルエラー:reified型パラメータはインライン関数でのみ使用できます。
正しい使用:
inline fun <reified T> goodFunction() {}
物語
プロジェクトで、任意の型にJSON文字列を一般的にパースする必要があり、ジェネリックパラメータを用いた関数を使用しました。
fun <T> parse(json: String): Tという標準の実装は、型消去のためにコレクションやジェネリックモデルのパースには正しく機能しませんでした。inlineとreified型を通じて解決し、問題が解消されました。
物語
開発者の一人が、通常のコンストラクタ
T()を使用してT型のインスタンスを作成しようとしたが、インラインおよびreifiedを使用していなかったため、コンパイル時にエラーが発生しました。型に関する情報が消去されていたためです。inline fun <reified T: Any>として書き換えることで、言語の標準的な手法で解決できました。
物語
通常の関数(インラインでない)で
reifiedを使用しようとした際に—IDEは混乱を招くコンパイルエラーを表示しました。開発者は原因を長い間探しましたが、ドキュメントを調べて関数を修正し、インラインを追加しました。