スコープ関数とは
Kotlinの標準ライブラリに定義されているジェネリック関数。
ジェネリック関数なので、どんな型にも適用できる関数です。
スコープ関数を使うことで、よりKotlinらしいコードが書けます。
letとrun
Streamのmap関数のようなイメージです。
val str: String = "5963"
// 変数strをIntに変換する
// letを使った場合
val i: Int = str.let { it.toInt() }
// 変数strをIntに変換する
// runを使った場合
val i2: Int = str.run { this.toInt() }
letに続くラムダ式は引数が1つです。この引数はstrへの参照です。
runに続くラムダ式は引数がありません。代わりに、このラムダ式内のthis参照はstrです。
ラムダ式の結果がlet、runの戻り値となります。
また、今回の例の変数strのような、関数の呼び出されるオブジェクトをレイシーバーオブジェクトといいます。
使いどころ
fun getName(): String? = ""
fun makeGreeting(name: String) = "Hello, $name"
fun greet(): String? {
val name = getName()
if (name == null) {
return null
}
return makeGreeting(name)
}
greet()関数では
getName()の結果を、makeGreeting()関数に渡し、
その結果がgreet()関数の戻り値となります。
ただし、getName()の戻り値はnull許容型なので、一度nullチェックが必要です。
これを、letを使って書き換えてみます。
fun greet(): String? {
return getName()?.let { makeGreeting(it) }
}
getName()の結果を安全呼び出しを使い、letを呼び出します。
こうすると、かなりスッキリ書けます。
安全呼び出しや、安全キャストの結果を関数の引数に渡す場合に便利です。
(もちろん、それ以外の場合にもよく使われます。)
applyとalso
letとrunに似ていますが、戻り値は常にレシーバーオブジェクトです。
val str: String = "5963"
// 変数strを標準出力
// alsoを使った場合
val str2: String = str.also { print(it) }
// 変数strを標準出力
// applyを使った場合
val str3: String = str.apply { print(this) }
使いどころ
class Person {
var firstName: String? = null
var middleName: String? = null
var lastName: String? = null
}
fun registerNewPerson() : Person {
val person = Person()
person.firstName = "久美子"
person.middleName = "スーザン"
person.lastName = "山本"
return person
}
registerNewPerson関数では、Personのインスタンスを新たに作って返します。
Personを初期化するだけですが、一旦変数に置かなければなりません。
alsoを使ってみましょう。
fun registerNewPerson() : Person {
return Person().also {
it.firstName = "久美子"
it.middleName = "スーザン"
it.lastName = "山本"
}
}
Personの一時変数を作らずに実装できます。
Builderパターンでは無いオブジェクトを扱う場合などに、
そのオブジェクトの初期化処理がスコープ関数の中にまとまるので、可読性向上につながります。
with
withはちょっと変わりダネです。
レシーバーオブジェクトを引数で渡すrun っといったところです。
val str = "5963"
val i: Int = with(str) { this.toInt() }
使いどころ
class Greeter {
fun greet(): String = "Hello, world"
}
fun greet(greeter: Greeter) = with(greeter) {
greet()
}
withを使って単一式関数にします。
this参照が変わり違った文脈で記述できるようになります。