Kotlin KoansでKotlin入門　第１０回：Smart casts

# はじめに
公式の問題集[「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://play.kotlinlang.org/koans/Classes/Smart%20casts/Task.kt)
次の Java コードを[smart cast](https://kotlinlang.org/docs/typecasts.html?&_ga=2.163441145.47448449.1647255356-1976109019.1644486873#smart-casts)と[when式](https://kotlinlang.org/docs/control-flow.html#when-expression)を使って書き直します。
```Java
public int eval(Expr expr) {
    if (expr instanceof Num) {
        return ((Num) expr).getValue();
    }
    if (expr instanceof Sum) {
        Sum sum = (Sum) expr;
        return eval(sum.getLeft()) + eval(sum.getRight());
    }
    throw new IllegalArgumentException("Unknown expression");
}
```

修正前のコード
```Kotlin
fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> TODO()
            is Sum -> TODO()
            else -> throw IllegalArgumentException("Unknown expression")
        }

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
```


# 問題のポイント
[smart cast](https://kotlinlang.org/docs/typecasts.html?&_ga=2.163441145.47448449.1647255356-1976109019.1644486873#smart-casts)と[when式](https://kotlinlang.org/docs/control-flow.html#when-expression)を使った問題です。

## smart cast
Kotlinでは、ほとんどの場合、明示的なキャスト演算子を使う必要はありません。なぜなら、コンパイラは、不変値に対するis-checkと明示的なキャストを追跡し、必要な場合は自動的に（安全な）キャストを挿入してくれるからです。
```Kotlin
fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x は自動的に String にキャストされる
    }
}
```
コンパイラは賢いので、事前に型チェックをしていればキャストは安全であると知っています。
```Kotlin
if (x !is String) return
print(x.length) // x は自動的に String にキャストされる
```

スマートキャストは、when式やwhileループでも有効です。今回の問題ではこれを使います。
```Kotlin
when (x) {
    is Int -> print(x + 1)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
}
```

## when式
when式は、複数の分岐を持つ条件式を定義する場合です。switch文のようなものです。
```Kotlin
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}
```



# 解答例
when式で```Num```型の場合は、プロパティ```value```を取得できます。
```Sum```型の場合は、```Expr```型のプロパティ```left```、```right```が取得できるので、これらを引数に```eval```関数を呼び出し、取得した値を足します。
```Kotlin
fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> expr.value
        	is Sum -> eval(expr.left) + eval(expr.right)
            else -> throw IllegalArgumentException("Unknown expression")
        }

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
```