まずはこんな記述があります。
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を返す。空じゃない場合はisMoge
とisHoge
を判定する。判定した結果どちらも当てはまらない場合はnullを返す。
というロジックを正しく書ける。
環境
Kotlin v1.5.21
コメント