第３５回：Delegates example

# はじめに
公式の問題集[「Kotlin Koans」](https://play.kotlinlang.org/koans/overview)を解きながらKotlinを学習します。

過去記事はこちら
- Introduction
  - [第０回：Kotlin Koansについて](https://qiita.com/kosuke1/items/41d192af63485bfc8cb8)
  - [第１回：Simple Functions](https://qiita.com/kosuke1/items/5862a3ece96082a62e67)
  - [第２回：Named arguments](https://qiita.com/kosuke1/items/2af11262852ee41b5da7)
  - [第３回：Default arguments](https://qiita.com/kosuke1/items/16cb8ac780df58dc8054)
  - [第４回：Triple-quoted strings](https://qiita.com/kosuke1/items/52cfeed2c49b0252d40e)
  - [第５回：String templates](https://qiita.com/kosuke1/items/0221bbbc5bc70847be6f)
  - [第６回：Nullable types](https://qiita.com/kosuke1/items/aa96e422c5313b6961bc)
  - [第７回：Nothing type](https://qiita.com/kosuke1/items/1ca0e48820d58c9dfe16)
  - [第８回：Lambdas](https://qiita.com/kosuke1/items/8de74f9491e003127f53)
- Classes
  - [第９回：Data classes](https://qiita.com/kosuke1/items/1be2de1b4406b8d914bf) 
  - [第１０回：Smart casts](https://qiita.com/kosuke1/items/50bdecaa0740eb0e1a17)
  - [第１１回：Sealed classes](https://qiita.com/kosuke1/items/71a4da02fe1e99da5d63)
  - [第１２回：Rename on import](https://qiita.com/kosuke1/items/f11465cc15a94e7589a3)
  - [第１３回：Extension functions](https://qiita.com/kosuke1/items/d4a1da00bc142c297221)
- Conventions
  - [第１４回：Comparison](https://qiita.com/kosuke1/items/e9486d044cae32167f36) 
  - [第１５回：Ranges](https://qiita.com/kosuke1/items/797f049ce5f33b1810c9)
  - [第１６回：For loop](https://qiita.com/kosuke1/items/f5f6eeea41fb89b2a20c)
  - [第１７回：Operators overloading](https://qiita.com/kosuke1/items/9845f98a632121f1493b)
  - [第１８回：Invoke](https://qiita.com/kosuke1/items/7879f83341d169374eb3)
- Collections
  - [第１９回：Collections Introduction](https://qiita.com/kosuke1/items/af91a0bd505cd93a3900) 
  - [第２０回：Sort](https://qiita.com/kosuke1/items/ed9a4b36f8573fc65a8f)
  - [第２１回：Filter map](https://qiita.com/kosuke1/items/45e70bac73706643e40c)
  - [第２２回：All, Any, and other predicates](https://qiita.com/kosuke1/items/daa940bf57e93d198ce4)
  - [第２３回：Associate](https://qiita.com/kosuke1/items/a4d8b0701b6848d43473)
  - [第２４回：Group By](https://qiita.com/drafts/d2279add0e79cbe19f01/edit)
  - [第２５回：Partition](https://qiita.com/kosuke1/items/d2279add0e79cbe19f01)
  - [第２６回：FlatMap](https://qiita.com/kosuke1/items/f08f22de98d736df6e12)
  - [第２７回：Max min](https://qiita.com/kosuke1/items/f2af0574bbc594bbe494)
  - [第２８回：Sum](https://qiita.com/kosuke1/items/477c2fd0886231440d06)
  - [第２９回：Fold](https://qiita.com/kosuke1/items/9b6ca3ab409335897adf)
  - [第３０回：Compound tasks](https://qiita.com/kosuke1/items/66949d40ce744bc696cb)
  - [第３１回：Sequences](https://qiita.com/kosuke1/items/f62212f67bde03298f11)
  - [第３２回：Getting used to the new style](https://qiita.com/kosuke1/items/80212483f696357496e6)
- Properties
  - [第３３回：Properties](https://qiita.com/kosuke1/items/0fa3e94b6ad1fe0440fd)
  - [第３４回：Lazy property](https://qiita.com/kosuke1/items/bc295546a00a054af1d1)

# 問題
[Delegates example](https://play.kotlinlang.org/koans/Properties/Delegates%20examples/Task.kt)

[デリゲートプロパティ](https://kotlinlang.org/docs/delegated-properties.html)について学び、デリゲートを使ってプロパティを遅延させます。

```修正前コード.kt
class LazyProperty(val initializer: () -> Int) {
    val lazyValue: Int by TODO()
}
```

# 問題のポイント
一般的なプロパティの中には、必要な都度手動で実装してもよいものがありますが、一度実装してライブラリに追加し、後で再利用する方が便利です。例えば
- レイジープロパティ：最初のアクセス時のみ値が計算される。
- Observableプロパティ：このプロパティの変更についてリスナーに通知される。
- 各プロパティに対して個別のフィールドを用意するのではなく、マップにプロパティを格納する。

これらの（そして他の）ケースをカバーするために、Kotlinはデリゲートプロパティをサポートしています。

```Kotlin
class Example {
    var p: String by Delegate()
}
```
構文としては、`val/var <プロパティ名>:<Type> by <expression>`です。
`by`の後の式はデリゲートです。なぜなら、プロパティに対応する`get()`と`set()`は、その`getValue()`と`setValue()`メソッドにデリゲートされることになるからです。
プロパティのデリゲートはインターフェースを実装する必要はありませんが、`getValue()`（`vars`の場合は`setValue()`）を提供する必要があります。

```Kotlin
import kotlin.reflect.KProperty

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}
```
`Delegate`のインスタンスに委譲された`p`から読み込むとき、`Delegate`の`getValue()`関数が呼び出されます。
その第一引数には`p`を読み込んだオブジェクトが、第二引数には`p`自身の説明（例えば、名前を取る）が入ります。

```Kotlin
val e = Example()
println(e.p) // Example@33a17727, thank you for delegating 'p' to me!
```

同様に、`p`に代入する場合は、`setValue()`関数が呼び出されます。
最初の2つのパラメータは同じもので、3つ目のパラメータには代入される値が格納されます。

```Kotlin
e.p = "NEW"
// NEW has been assigned to 'p' in Example@33a17727.
```

## Lazy properties﻿
Kotlinの標準ライブラリは、いくつかの便利な種類のデリゲートのためのファクトリーメソッドを提供します。
lazy() はラムダを受け取り、Lazy<T> のインスタンスを返す関数で、遅延プロパティを実装するためのデリゲートとして使用することができます。
get() の最初の呼び出しは、lazy() に渡されたラムダを実行し、その結果を記憶しています。それ以降の get() の呼び出しは、単に記憶された結果を返します。

```Kotlin
val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)
    println(lazyValue)
}
// computed!
// Hello
// Hello
```

# 解答例
```Kotlin
class LazyProperty(val initializer: () -> Int) {
    val lazyValue: Int by lazy(initializer)
}
```