KotlinのRun, Let, Apply, Alsoを使い分け

**※ あくまでも自分の見解です。**

## 概要

最近の悩みはrun, let, apply, alsoをどうやって使い分けです。
基本の機能は簡単に分けれます。run, letは戻り値を期待してない、apply, alsoは同じ型を望んでます。
（この辺の使い方は他に沢山の記事がありますので、割愛させてくださいませ :bow: ）

問題は、じゃあ、「runとlet」と「applyとalso」の差は何でしょうか。
頑張れば全部「let」で実装できるのに、「thisとit」を分ける意味がわかりません！


## 公式ページの推奨

先ずは公式ページを見てみましょう。

> Are you calling methods on multiple objects in the block, or passing the instance of the context object as an **argument**? If you are, use one of the functions that allows you to access the context object as it, not this (also or let).

つまり、引く数として他の値に渡すかどうかです。

例えば下の例なら、「it」を使うのが推奨です。
このScopeの中で「it」は変化はしません、一貫性を持ちます。

```kotlin

// Context object is 'it'
class Baz {
    var currentBar: Bar?
    val observable: Observable

    val foo = createBar().also {
        currentBar = it                    // Accessing property of Baz
        observable.registerCallback(it)    // Passing context object as argument
    }
}
```

また、自分自身に対する変更は「this」を使います。
なので、基本的に「this」が出る時は書き方がよくないと思っても良いでしょう。

```kotlin

// Context object is 'this'
class Baz {
    val foo: Bar = createBar().apply {
        color = RED    // Accessing only properties of Bar
        text = "Foo"
    }
}
```


## ニュアンスから想像しましょう

使い方が分かりましたけど、実際にCodeを書くときは忘れてしまいそう。
なので、想像して納得しましょう。

以下は私の考えです、一応参考まで。

### **Run**

「私が実行します！」と自分自身でいろいろやります。
そして、その結果は誰も望んでません。

例：Toolbarを設定する

```kotlin

var toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setNavigationIcon(R.drawable.icon)
toolbar.setNavigationOnClickListener(view -> doSomething())

//run
findViewById<Toolbar>(R.id.toolbar)
  .run {
    setNavigationIcon(R.drawable.icon)
    setNavigationOnClickListener({ doSomething() })
  }
```

同じObjectが何回も実行する時に、ちょっとだけ便利になるくらいです。
あまり役に立たないかもしれません。:frowning2:

### **Let**

「Let it be」のような感じで、この子を他のところに行かせよう。
「自分から他人に」、自身は何も変化しません。

例：Intentを渡す前にnull check

```kotlin

val intent = getIntent()
if (intent != null) {
  setIntent(intent)
}

//let
getIntent()?.let { setIntent(it) }
```

定番の引数を渡すCaseです。
何かを渡したい時は「let」を使えば良いと思います。

### **Apply**

「私に応用する」、自分自身に何かを反映する。
自分を渡す前にもう一回自分を強化するイメージです。

例：FragmentのnewInstance

```kotlin

fun newInstance(bundle: Bundle): FooFragment{
  var fragment = FooFragment()
  fragment.setArguments(bundle)
  return fragment
}

//apply
fun newInstance(bundle: Bundle): FooFragment{
  return FooFragment().apply {
    setArguments(bundle)
  }
}
```

同じ定番のBundleを設定するCaseです。
何かを返却する前に、Objectの値をいじりたい時に使いましょう。

### **Also**

「ついでに」です。この値を渡す前に、**ついでに**他の値にも渡します。
何かを提出前に、他の人にもチラ見せします。 |дﾟ)

例：getInstanceの返却

```kotlin

fun getInstance(context: Context): FooDatabase {
  if (INSTANCE != null) {
    return INSTANCE
  } else{
    INSTANCE = buildDatabase(context)
    return INSTANCE
  }
}

//also
fun getInstance(context: Context): FooDatabase {
  if (INSTANCE != null){
    return INSTANCE
  } else{
    return buildDatabase(context).also { INSTANCE = it }
  }
}

//もっと省略
fun getInstance(context: Context): FooDatabase {
  return INSTANCE ?: buildDatabase(context).also { INSTANCE = it } |
}
```

他の子にも見せたい時に使いましょう。
公式によると、特に「it」を使いたくない時にも使えまう。
例えば `LOG.info("Something created")`とかのLog系。

### 他のかたの考え

また、こちらの考えも面白いです。
[Example of when should we use run, let, apply, also and with on Kotlin (stackoverflow)](https://stackoverflow.com/questions/45977011/example-of-when-should-we-use-run-let-apply-also-and-with-on-kotlin/45978893#45978893)

### 複雑になった場合

複雑になった時は無理に一個のScope Functionで書かなくても良いです。
Chainができますので、複数個で解決しましょう。

```kotlin
getIntent()
  .let { intent ->
   sendIntent(intent.setData(data)) //itを弄らない
  }

getIntent()
  .apply {
    setData(fooData)
  }.let {
    sendIntent(it)
  }
```

## 終わり

~~Codeは動かせるだけではなくで、感じるんだ~~
一緒に綺麗なCodeを書きましょう :hushed: 

## 参考
- [Kotlin公式ページ](https://kotlinlang.org/docs/reference/coding-conventions.html#using-scope-functions-applywithrunalsolet)
 
- [Example of when should we use run, let, apply, also and with on Kotlin (stackoverflow)](https://stackoverflow.com/questions/45977011/example-of-when-should-we-use-run-let-apply-also-and-with-on-kotlin/45978893#45978893)

- [googlesamples (github)](https://github.com/googlesamples/android-architecture-components/blob/master/BasicRxJavaSampleKotlin/app/src/main/java/com/example/android/observability/persistence/UsersDatabase.kt#L36-L39)

**更新：例を追加しました。(06/14)**