Kotlin スコープ関数の使い分け

#まとめ
使い分けのポイントはたったの2つだけ！

- 対象のオブジェクトのブロック内引数を **「`it` にしたいか」** or **「`this` にしたいか」**
- 戻り値を**「自分で指定したいか」** or **「対象のオブジェクトにしたいか」**

<img width="1064" alt="スクリーンショット 2019-08-02 16.14.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306161/16624435-d403-0b2b-4465-bb097ad5b1ed.png">

#はじめに
スコープ関数をプロジェクトで使用する頻度が増えてきたので、この機会に私なりの見解でまとめてみました。

繰り返しになりますが、意識するポイントは**「引数」**と**「戻り値」**の2つだけです。

(`let`, `run`, `also`, `apply` それぞれの定義についてはまとめて[コチラ](https://qiita.com/yasuX/items/20b6354d42b19879a55e#%E5%AE%9A%E7%BE%A9%E3%81%BE%E3%81%A8%E3%82%81)に載せました。)
(また、使用頻度が低いため `with` については省略をしました。)

# 引数
ポイントは、

**「ブロック内の引数を、 `it` にするか `this` にするか」**

です。
それぞれの特長は以下のようです。

## it
- 名前を変えられるので引数の意味がわかりやすくなる。


```Kotlin
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
```
これが、

```Kotlin
User().also { person ->
    nameTxt.text = person.name
    ageTxt.text = person.age.toString()
    hobbyTxt.text = person.hobby
}
```
こうなる。
`this`の方でもいけますが、感覚的にはこんな感じです。
（もっとわかりやすい例があると思いますが、すみません。）

## this
- `this`を省略できる。

```Kotlin
val toast = Toast.makeText(this, "message", Toast.LENGTH_SHORT)
toast.setGravity(Gravity.CENTER, 0, 0)
toast.setMargin(10.0f, 10.0f)
toast.show()
```
これが、

```Kotlin
Toast.makeText(this, "message", Toast.LENGTH_SHORT).apply {
    setGravity(Gravity.CENTER, 0, 0)
    setMargin(10.0f, 10.0f)
    show()
}
```
こうなる。
`toast` が何回も表示されていたのが、スッキリしました。

以上より、
名前を決めたいなら `it`, 

```Kotlin
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)
※コードの意味は特にありません。

```Kotlin
val intent = Intent(this, SecondActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addCategory("sample")
startActivity(intent)
```
まとめの表に従うと、
まず、戻り値は必要でないので、対象のオブジェクトにしましょう。
引数はどちらでもいいと思いますが、個人的には`this`ですかね。
よって、`apply`を使います。


```Kotlin
Intent(this, SecondActivity::class.java).apply {
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    addCategory("sample")
    startActivity(this)
}
```

#練習問題(2)
※こちらも特にコードに意味はありません。

```Kotlin
val contents = getContents()
val master =
    if (contents != null) {
        println(contents)
        contents
    } else {
        throw Exception()
    }

private fun getContents(): String? = "Contents"
```
この場合は戻り値が必要なので、`自分で指定できる`方を選択します。
引数は`this`だと内容がわかりにくくなるので、`it`。
よって`let`を使用します。すると、以下のように記述できます。

```Kotlin
val master = getContents()?.let { contents ->
    println(contents)
    contents
} ?: throw Exception()
```
どうでしょうか？かなりスッキリ書けたのではないでしょうか。
スコープ関数万歳！(エルビス演算子の効果もありますが。)


#定義（まとめ）
以下のようにまとまって定義が載ってるサイトが少なかったので、比較しやすいようにまとめて載せました。是非、感覚的にイメージを掴んだ後にコードに立ち戻って定義を理解しましょう。

```Kotlin
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のスコープ関数使いたがり症候群でちゃう。


#参考
https://qiita.com/ngsw_taro/items/d29e3080d9fc8a38691e