🏄

Kotlinのwhen式で早期リターンしたい

2023/02/18に公開

はじめに

when式のブロック内の処理で、早期リターンしたいと思うことがありました。
return@when emptyList()みたいに書けると思いきや、文法エラーで怒られました。。

TL;DL

早期リターンしたいブロックの返り値をletにすることで擬似的に早期リターンできました。

val foo = listOf(1, 2)
val condition1 = true
val condition2 = true

val bar = when (foo.size) {
    // foo.sizeが1の時の返り値はlet
    1 -> let {
        if (condition1 && condition2) {
            // 厳密にはletに対して早期リターン
            // letの値がそのままwhenの返り値になるため、擬似的に早期リターン成功!!
            return@let 1
        }
        2
    }
    else -> {
        3
    }
}
println(bar)

関数化しろよというツッコミはご容赦ください。
多くのシーンでは関数化すべきだと思います🙁

関数で対応する場合(推奨)

val bar = when (foo.size) {
    1 -> {
        returnWhen1(condition1, condition2)
    }
    else -> {
        3
    }
}
println(bar)

fun returnWhen1(condition1: Boolean, condition2: Boolean): Int {
    if (condition1 && condition2) {
        return 1
    }
    return 2
}

ちなみにうまくいかなかった対応

labelで名前をつけることでジャンプすることができます。
これを使用しどうにかできないかなと思いましたが、うまくいきませんでした。

https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/returns.html

when式自体にlabelをつけてみた

val bar = whenLabel@ when (foo.size) {
    1 -> {
        if (condition1 && condition2) {
            return@whenLabel 1
        }
        2
    }
}

when式の対象ブロックにlabelをつけてみた

これならできるのではと期待はありました。
letに近い対応で、labelがあればreturnできるようになる…とは行きませんでした🥲

val bar = when (foo.size) {
    1 -> whenLabel@ {
        if (condition1 && condition2) {
            return@whenLabel 1
        }
        2
    }
}

まとめ

when式では早期リターンできませんでした。
ちなみにif式も同様で、同じ方法で対応できました。

whenやifは式で、letやforEachは関数だからできないのかと思いましたが、for文はlabelに対応しているんですよね🤔
言語上の成約があるのか、関数化しろという思想なのか。
大人しく関数化しておきましょう。。

参考

Returns and Jumps - Kotlin Programming Language

Discussion