技術関係

【Kotlin】kotlinのwhenの使い方は気をつけよう。when式は引数の値を条件にする

まずはこんな記述があります。

val hogeList: List<String> = emptyList()
val isMoge = true
val isHoge = false

val message = when (hogeList.isNotEmpty()) {
    isMoge -> {
        "もげ"
    }
    isHoge -> {
        "ほげ"
    } else -> null
}
println(message) // ほげ

// hogeListが空なのでnullが返ってほしいはずなのに ほげ が返る

hogeListが空の場合はnullを返そう。hogeListが空じゃない場合はisMogeがtrueかだったらもげを返そう。

isMogeがfalseだったらisHogeがtrueかどうかを判定してtrueならほげを返そう。両方falseならnullを返そう。

 

そんな事をwhenを使ってこう書けると思い込むと意図した結果にならない。

実際にkotlinのwhen 使い方を見てみる

まず、whenの最初の引数に渡した値がブロック内の判定に使われる。

ここで言うhogeList.isNotEmpty()の値、つまりは 「true」

「hogeListが空じゃなかったら〜」という条件にはならずに「true」がブロック内での判定に使われる。

val message = when (hogeList.isNotEmpty()) {
    // ここでやっていることは true == isMoge という意図しないものに。 
    isMoge -> { 
        "もげ"
    }
    // true == isHoge はisHogeがtrue なのでこの条件に一致。結果、「ほげ」が返る。
    isHoge -> {
        "ほげ"
    } else -> null
}

「trueはisMogeと同じ値か? それともtrueはisHogeと同じ値か?」ということをコードでは判定していることになる。

上記の書き方でも当然コンパイルエラーは起こらないので、うっかりバグを生み出しやすい。

 

意図した結果を生み出すにはこう修正する。

val hogeList: List<String> = emptyList()
val isMoge = true
val isHoge = false

val message = when {
    hogeList.isNotEmpty() && isMoge -> {
        "もげ"
    }
    hogeList.isNotEmpty() && isHoge -> {
        "ほげ"
    }
    else -> null
}
println(message) // もげ

hogeList.isNotEmpty()をブロック内に持ってきて&&で繋げる。

条件が複数になると冗長に見えてしまうが他に書きようがないっぽい。

ともあれこれで

hogeListが空の場合はnullを返す。空じゃない場合はisMogeisHogeを判定する。判定した結果どちらも当てはまらない場合はnullを返す。

というロジックを正しく書ける。

環境

Kotlin v1.5.21

参考

https://kotlinlang.org/docs/control-flow.html

コメント

タイトルとURLをコピーしました