Kotlinにおけるインライン関数は、inlineキーワードを使用して定義され、コンパイラに関数の本体を呼び出しの場所に直接「挿入」するよう指示します。これは特にラムダや短い関数を使用する場合に関数の呼び出しコストを削減し、クロージャをキャプチャするための追加オブジェクトの割り当てを排除します。
例:
def inline fun synchronized(lock: Any, block: () -> Unit) { kotlin.synchronized(lock) { block() } }
主な利点:
欠点:
推奨: コードのクリティカルな部分でラムダが頻繁に使用される場合、パフォーマンスを向上させるためにinlineを使用します。
リファイメント型の引数を扱う際のインライン関数の制限は何ですか?
間違った回答がよくある: 「リファイメント型は、すべてのインライン関数内で常に利用可能です。」
正しい回答: インライン関数のみがジェネリクス宣言でreified修飾子を使用でき、ランタイムで型にアクセスを許可します:
inline fun <reified T> getTypeName() = T::class.java.name
通常のジェネリック関数では、実行時に型Tへのアクセスはありません。
物語
不適切に使用されたインラインによるAPKサイズの肥大化: Androidプロジェクトのチームでは、多くのユーティリティ関数にinlineが指定され、大きく複雑な本体を持つ関数も含まれていました。その結果、関数が全ての呼び出し場所で重複したため、APKのサイズがほぼ2MB増加しました。
物語
ラムダとプライベート変数へのアクセスに関するエラー: ラムダを含むインライン関数を使用し、その内部でクラスのプライベートメンバーにアクセスしていました。関数を外部モジュールに移動した後、コードがコンパイルできなくなり(権限が違反)、CIでのみ発見されました。
物語
インライン関数の外でのreifiedの使用: 開発者の一人が、インライン修飾子なしでreifiedジェネリックパラメータを持つ関数を宣言しようとしました。コードはコンパイルされず、なぜ「T::class」がインライン関数の外では利用できないのかを初心者が長時間調査することになりました。