#まとめ
使い分けのポイントはたったの2つだけ!
- 対象のオブジェクトのブロック内引数を 「
it
にしたいか」 or 「this
にしたいか」 - 戻り値を**「自分で指定したいか」** or 「対象のオブジェクトにしたいか」
#はじめに
スコープ関数をプロジェクトで使用する頻度が増えてきたので、この機会に私なりの見解でまとめてみました。
繰り返しになりますが、意識するポイントは**「引数」と「戻り値」**の2つだけです。
(let
, run
, also
, apply
それぞれの定義についてはまとめてコチラに載せました。)
(また、使用頻度が低いため with
については省略をしました。)
引数
ポイントは、
「ブロック内の引数を、 it
にするか this
にするか」
です。
それぞれの特長は以下のようです。
it
- 名前を変えられるので引数の意味がわかりやすくなる。
val user = User()
nameTxt.text = user.name
ageTxt.text = user.age.toString()
hobbyTxt.text = user.hobby
// data class User(
// val name: String = "Taro",
// val age: Int = 20,
// val hobby: String = "Baseball"
// )
// nameTxt, ageTxt, hobbyTxtはそれぞれTextViewのid
これが、
User().also { person ->
nameTxt.text = person.name
ageTxt.text = person.age.toString()
hobbyTxt.text = person.hobby
}
こうなる。
this
の方でもいけますが、感覚的にはこんな感じです。
(もっとわかりやすい例があると思いますが、すみません。)
this
-
this
を省略できる。
val toast = Toast.makeText(this, "message", Toast.LENGTH_SHORT)
toast.setGravity(Gravity.CENTER, 0, 0)
toast.setMargin(10.0f, 10.0f)
toast.show()
これが、
Toast.makeText(this, "message", Toast.LENGTH_SHORT).apply {
setGravity(Gravity.CENTER, 0, 0)
setMargin(10.0f, 10.0f)
show()
}
こうなる。
toast
が何回も表示されていたのが、スッキリしました。
以上より、
名前を決めたいなら it
,
it.method1()
it.method2()
のようになるのであれば、this
(の省略)を使って
method1()
method2()
とするのがいいのではないかと思います。
戻り値
ポイントは、
「戻り値を、 自分で指定したもの
にするか 対象のオブジェクト
にするか」
です。
感覚的には以下のようになります。
##自分で指定する
xxxxx.let {
aaaaa = it
it.bbbbb
ccccc(it) <- 戻り値はコレ(ccccc(it))になる
}
##対象のオブジェクト
⬇ 戻り値はコレ(xxxxx)になる
xxxxx.also {
aaaaa = it
it.bbbbb
ccccc(it)
}
スコープ関数を使い始めのときはこのことがわかりませんでした。。。
しかし、このことがわかってからは
「Nullableのオブジェクトはletを使って処理すると良い」
ということの意味がようやくわかりました。
#練習問題(1)
※コードの意味は特にありません。
val intent = Intent(this, SecondActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addCategory("sample")
startActivity(intent)
まとめの表に従うと、
まず、戻り値は必要でないので、対象のオブジェクトにしましょう。
引数はどちらでもいいと思いますが、個人的にはthis
ですかね。
よって、apply
を使います。
Intent(this, SecondActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory("sample")
startActivity(this)
}
#練習問題(2)
※こちらも特にコードに意味はありません。
val contents = getContents()
val master =
if (contents != null) {
println(contents)
contents
} else {
throw Exception()
}
private fun getContents(): String? = "Contents"
この場合は戻り値が必要なので、自分で指定できる
方を選択します。
引数はthis
だと内容がわかりにくくなるので、it
。
よってlet
を使用します。すると、以下のように記述できます。
val master = getContents()?.let { contents ->
println(contents)
contents
} ?: throw Exception()
どうでしょうか?かなりスッキリ書けたのではないでしょうか。
スコープ関数万歳!(エルビス演算子の効果もありますが。)
#定義(まとめ)
以下のようにまとまって定義が載ってるサイトが少なかったので、比較しやすいようにまとめて載せました。是非、感覚的にイメージを掴んだ後にコードに立ち戻って定義を理解しましょう。
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T, R> T.run(block: T.() -> R): R = block()
public inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
#おわりに
Kotlinのスコープ関数使いたがり症候群でちゃう。