Kotlin KoansでKotlin入門 第10回:Smart casts


はじめに

公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。

過去記事はこちら

問題

Smart casts
次の Java コードをsmart castwhen式を使って書き直します。

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");
}

修正前のコード

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 castwhen式を使った問題です。

smart cast

Kotlinでは、ほとんどの場合、明示的なキャスト演算子を使う必要はありません。なぜなら、コンパイラは、不変値に対するis-checkと明示的なキャストを追跡し、必要な場合は自動的に(安全な)キャストを挿入してくれるからです。

fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x は自動的に String にキャストされる
    }
}

コンパイラは賢いので、事前に型チェックをしていればキャストは安全であると知っています。

if (x !is String) return
print(x.length) // x は自動的に String にキャストされる

スマートキャストは、when式やwhileループでも有効です。今回の問題ではこれを使います。

when (x) {
    is Int -> print(x + 1)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
}

when式

when式は、複数の分岐を持つ条件式を定義する場合です。switch文のようなものです。

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

解答例

when式でNum型の場合は、プロパティvalueを取得できます。
Sum型の場合は、Expr型のプロパティleftrightが取得できるので、これらを引数にeval関数を呼び出し、取得した値を足します。

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