【Kotlin練習問題】スマートキャスト

スマートキャストとは

KolinではJavaのように毎回明示的にキャストをする必要はありません。コンパイラがキャスト前の変数が明らかにキャスト後の変数と一致していると判断できる場合には自動的に安全なキャストが挿入されるようになっています。これをスマートキャストと呼びます。

例えば以下のコードではxは自動的にキャストされます。

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

if文の条件文の中でxがStringであることをチェックしており、Stringであればlengthを出力するというコードですが、if文のボディでは条件文がtrue、すなわちxがStringであることが確定しているので、lengthを出す際にわざわざキャストしなくてもいいということです。

逆に以下のようにStringじゃなければreturnさせていれば、その後のreturnされていないコードではxはStringなので、同様にスマートキャストが適用されます。

if (x !is String) return

print(x.length) // xは自動的にStringにキャストされている

スマートキャストはwhen文を使用したコードでも適用されます。

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

when文の一つ目ではIntである場合の処理ですので、xはIntにスマートキャストされ、x+1も問題なく処理されます。以降の文も同様です。

スマートキャストは変数のチェックとその変数が使用されるまでの間に変数の中身が変わっていないということをコンパイラが確認できる場合にのみ有効です。具体的には以下のようなに決められています。

  • valローカル変数はローカル委譲プロパティを除いて有効です。
  • valプロパティはそれがプライベート、または内部、またはそのプロパティが宣言されたモジュール内でチェックが行われていれば有効です。公開されているプロパティやカスタムゲッターをもっているプロパティに対してはスマートキャストは使えません。
  • varローカル変数はチェックと使用までの間に変更されていない場合と、その変数を変更しているラムダ式に使用されていない場合、そしてローカル委譲プロパティでない場合のみ有効です。
  • varプロパティに対しては常に無効です。varプロパティはコードのいつ、どこからでも変更される可能性があるためです。

問題

以下のJavaコードをスマートキャストとwhenを使ってKotlinで書き換えてください。

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

Kotlin Playgroundでコードの編集・動作確認ができます。

[expander_maker id=”1″ more=”答え” less=”非表示”]

答え

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

[/expander_maker]

その他の問題はこちらからどうぞ。

完全無料で通えるプログラミングスクール

プログラミング学習はどうしても一人だとつまづいてしまう時がきます。調べればわかることも少なくないですが、最初のうちは調べ方もわからないことが多いため、あまり効率的ではありません。

効率的かつ挫折せずにプログラミングを学習したい方はスクールを検討してみるのも一つの手です。

中には無料で通えるスクールや、就職保証をしてくれるスクールなどもあるので、きっとあなたの目的に応じて最適のスクールが見つかります!以下の記事で評判がよく特におすすめのスクールをいくつかピックアップしているので、スクール選びで後悔したくない方は御覧ください!

https://codelabsjp.net/best-programming-school/

おすすめ書籍

Kotlinの文法をまず学びたい!という方には以下の書籍がおすすめです。Kotlinは日本語書籍がまだ豊富とは言えない状況ですが、細かく解説されており、Kotlin入門者のかたでもつまずくことなく学習できると思います。

[itemlink post_id=”1743″]

実際にアプリを作りながら覚えていきたい!という方には以下もお勧めです。はじめに上の書籍で文法をさらっと学んでから取り組むのがお勧めです。

[itemlink post_id=”1745″]