Kotlinのスコープ関数("スコープ関数")は、オブジェクトのコードブロックの実行コンテキストを管理するための標準関数(let, also, run, apply, with)です。これらは以下の点で異なります:
itまたはthisを介してどのようにアクセスされるか。| 関数 | this/it | 戻り値 | 目的 |
|---|---|---|---|
| let | it | 結果 | チェーン操作、nullableの処理、map |
| also | it | オブジェクト | 副作用、ロギング、デバッグ |
| run | this | 結果 | 計算、戻り値付きの初期化 |
| apply | this | オブジェクト | オブジェクトの設定、ビルダー |
| with | this | 結果 | 外部APIとの作業、"外部"オブジェクトの処理 |
例:
let:オブジェクトがnullableの場合に便利です:val str: String? = "Text" str?.let { println(it.length) }
apply:オブジェクトの設定:val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
run:オブジェクトで実行し、結果を返します:val length = "abcde".run { length }
with:外部オブジェクトとの作業に使用:val sb = StringBuilder() with(sb) { append("Hello, ") append("world!") toString() }
also:副作用用(例えば、ログ):val list = mutableListOf(1, 2, 3) list.also { println("Before: $it") }.add(4)
itにオブジェクトのコピーを作成し、オブジェクトのプロパティを変更するのはあまり便利ではありません。this / it)を返します。ビルダーに役立ちます。withは通常の関数であり、拡張関数ではありません。letとalsoの違いは何ですか?
回答:
itを使用します。letはラムダの結果を返し、チェーン変換にしばしば使用されます。alsoは元のオブジェクトを返し、副作用(ログ、デバッグ)に使用され、変換チェーンに干渉しません。例:
val result = listOf(1).also { println(it) }.map { it * 2 } // 結果はList<Int>
物語
初心者は、オブジェクトを"チェーン"で変更できると考えてletを使用しました。その結果、設定ブロックの完了後にオブジェクトではなく、ラムダの結果(例えば、何もない)を返すため、DSLの構築チェーンが壊れました。
物語
nullableオブジェクトを扱うコードを書く際、letの代わりにrunを使用し、戻り値の違いに気づきませんでした。その結果、期待される結果と異なる式の結果が得られ、nullが存在するはずのない箇所に現れ、アプリケーションのロジックが崩壊しました。
物語
大きなビルダーで、内部オブジェクトについてwithを誤って使用し、拡張パターンを期待しました。withは拡張関数ではないため、複数のwithブロックのチェーンが正しく機能せず、内部呼び出しが混乱し、現在のオブジェクトの範囲を超えてしまいました。オブジェクトの作成の階層を完全に書き直さなければなりませんでした。