Kotlinのapplyをじっくりと読む

Kotlinのapplyを理解していく過程で色々勉強になったので、その過程をそのまま✏️。

```kotlin
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}
```

（```kotlin.internal.contracts.Standard.kt```より）


<br>
ひとつずつ何が書いてあるか理解していく。

## **```public```**の部分
```public``` は可視性修飾子。どこからでも参照可能であることを意味している。

```kotlin
public
```
<br>
## **```inline```**の部分
```inline``` はinline関数にするための修飾子。

```kotlin
inline
```
関数型を引数にもつ関数を定義するとき、実行時に無名クラスをたくさん作ってオーバーヘッドを起こさないようにする目的で使用される。```inline```修飾子をつけておくと、コンパイラが```inline```宣言されている関数を呼び出しているコードの箇所に直接関数本体を置換する。
（確認したい場合は実際にデコンパイルしてみると良い。）
<br>
## **```fun```**の部分
```fun``` は関数宣言。関数を定義することを意味している。

```kotlin
fun
```

<br>
## **```<T>```**の部分
```<T>``` は型パラメータ。慣習で```T```という文字が使用されることが多い印象。（Typeの”T”なのかな？と勝手に思っている。知っている人教えてください）

```kotlin
<T>
```
<br>
型パラメータのシンプルな例。クライアントによって、```T```は任意の型になる。

```kotlin
sample("hoge") // この場合だと、任意の型TはString型と推論される。
sample(1) // この場合だと、任意の型TはInt型と推論される。

fun <T> sample(t: T) {
    println(t?.hashCode())
}
```

<br>
## **```T.apply()```**の部分
```T.apply()``` はKotlinの拡張関数。任意の型```T```の拡張関数```apply```を定義するという意味。

```kotlin
T.apply()
```

拡張関数は```[型名].[関数名]```という書き方をする。
もちろん拡張関数は、任意の型T出なくても作ることができる。
参考までに```String```型で拡張関数を作ってみると、こんな感じ。

```kotlin
println("hoge".toQuestion()) // 拡張関数を使って「hoge」を「hoge?」にしてみる

fun String.toQuestion(): String {
    return this + "?"
}
```

<br>
## **```block: T.() -> Unit```**の部分
```block:```の```block```は引数の名前。 ```T.() -> Unit```は関数型。関数型も型の一種で、少し特徴的な印象はあるが、ぜひ```Int```型や```String```型などと同じくらいの親近感で接してあげたい。
```apply```という拡張関数は```block```という名前の、```T.() -> Unit```という関数型を引数にとるという意味。

```kotlin
block: T.() -> Unit
```

関数型は```[引数の型] -> [戻り値の型]```という書き方をする。

```kotlin
T.() -> Unit
```
これは```T.()```という引数をとり、戻り値はないという関数型という意味になる。

では、```T.()```という引数とは、いったい何者なのか。これは任意の型```T```をレシーバとすることを意味している。
レシーバオブジェクトには```this.```でアクセスすることができる。

```kotlin
"hoge".apply({
    this.toUpperCase() // レシーバオブジェクトにはthis.でアクセスできる。
})
```

突然ラムダ式を記載したが、ラムダは```{ }```で囲われた処理を関数の引数に渡すことができる。
レシーバ付きラムダは任意のレシーバオブジェクトのメソッドにアクセスできる。

ちなみにここでは明示的に```()```の中にラムダを書いて、関数の引数に渡したけど、
関数の引数がラムダ唯一であれば、丸括弧```()```は省略できるので、こう書き換えられる。

```kotlin
"hoge".apply {
    this.toUpperCase()
}
```

<br>
## **```: T```**の部分
```: T```は関数の返り値。```apply```という拡張関数は任意の型```T```を返すという意味。

```kotlin
: T
```

<br>
## ここで一旦整理
ここまでで、一旦整理。

つまりこれ↓は、

```kotlin
public inline fun <T> T.apply(block: T.() -> Unit): T
```
任意の型```T```の拡張関数を```apply```という名前で、どこからでもアクセス可能なinline関数として定義。
拡張関数の引数には```block```という名前の関数型をとり、その関数型は任意の型```T```のレシーバを引数にとり、戻り値はなし。
拡張関数の戻り値は任意の型```T```。


<br>
<br>
## 続いてapplyの中身、その前に再掲
続いて関数の中身を見ていく。その前に```apply```の定義を見る度に、だいぶページをスクロールしないといけなくなるので、復習も兼ねて再掲。

```kotlin
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}
```

<br>
## **```block()```**の部分
```apply``` 関数に渡された引数の関数オブジェクトを実行している。

```kotlin
block()
```

```apply``` を使用するときにラムダで関数オブジェクトを渡している。まさにその渡されたラムダ```{ }```の中身を実行している場所。

```kotlin
"hoge".apply {
    toUpperCase() // ここを実行している
}
```

<br>
## **```return this```**の部分
```return this``` は関数の戻り値。つまりここでは、任意の型```T```のオブジェクトが返却される。

```kotlin
return this
```

<br>
Androidアプリではこんな感じで使用することが多い印象。

```kotlin
val bundle = Bundle().apply {
    putString("HOGE", "hoge")
    putInt("FUGA", 1)
    putBoolean("IS_PIYO", true)
}
```
```apply``` の定義と照らし合わせると、

```kotlin
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}
```

```Bundle.apply{ }```の```{ }```囲われた部分が関数オブジェクトとして```apply```関数に渡されるので、```apply```関数の定義に書いてある```block()```では、渡された```{ }```の中の処理が順番に全部実行されることになる。



 - ```T``` …任意の型```T```は```Bundle```型
 - ```block()``` …関数オブジェクトを実行している部分は```putString("HOGE", "hoge”)``` 、```putInt("FUGA", 1)``` 、```putBoolean("IS_PIYO", true)``` 
 - ```return this``` …返り値の部分は実際に値を```put```した```Bundle```

ということ。

## 参考
いつもお世話になっている本
[Kotlin イン・アクション](https://shopping.yahoo.co.jp/product/j/9784839961749/compare.html)