[毎日Kotlin] Day9.Smart casts(スマートキャスト)

2018.01.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

毎日Kotlinシリーズです。

このシリーズを初めての方はこちらです。「毎日Kotlin」はじめました | Developers.IO

問題

Smart casts | Try Kotlin

JavaからKotlinに変換してみよう。

Rewrite the following Java code using smart casts and when expression:

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

狙い

ここで考えて欲しい問題の意図はなんだろうか?

スマートキャストはとっても便利です。よしなにやってくれるので助かります。今回の例だけでなく、いろんな場面でスマートキャストをしてくれるので、「え?すでにキャスト済み?」とびっくりすることも多々あります。JetBrains神ありがとう。

解答例

fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> expr.value
            is Sum -> eval(expr.left) + eval(expr.right)
            else -> throw IllegalArgumentException("Unknown expression")
        }

isinstanceof と同じ役割で使っています。それ以降に使う場合はすでにキャストされて使えるので便利です。 ((Num) expr)こんな感じでいちいちキャストする必要ありません。

型をチェックしたら、キャストしたのと同様に扱えます。

補足

「え?すでにキャスト済み?」とびっくりする例があります。これをうまいこと使って、コンパイルレベルで安全にコードを書いていきましょう。

    fun foo(str: String?) {
        if (str != null) {
        //?がいらない。not nullであることが推論され、スマートキャストされます
            str.length
        }
        
        str ?:return
        //?がいらない。not nullであることが推論され、スマートキャストされます
        str.length
    }

あとがき

Day10.でまたお会いしましょう。