すごいswitch文に出会った
Javaのリファクタリング案件でこんなコードに出会いました。
switch ( cmd ) {
case 0:
// 処理A
// fall through
case 1:
case 2:
// 処理B
break;
default:
// 処理C
break;
}
一見すると、 case 0
は 処理A
のみを実行するように見えますが、よくみると、 case 0
には break
がないので、実は 処理B
も実行されるんです!
最初は、 break
の書き忘れかな?と思いましたが、どうやら仕様通りの挙動でした。
フォールスルーという技だった
このように、意図的に break
を省略する記法を フォールスルー(fall through) と言うそうです。よく見たらコメントにも書いてありますね。
if
文で置き換えてみた
このフォールスルーは、とても面白いテクニックですが、誤読を招きやすく、バグの温床になると思ったので、残念ですが if
文に置き換えることにしました。
if ( cmd == 0 ) {
// 処理A
}
if ( cmd <= 2 ) {
// 処理B
} else {
// 処理C
}
うーん、変更前の方がシンプルだったかな?微妙です。でも誤読の心配はなくなりました。
ただ、もし cmd
が String
型だったら、こんな書き方はできないですね。悩みます。
もっと良い書き方があれば、どなたか教えてください。
フォールスルーできる言語とできない言語
他の言語の事情が気になったので、軽く調べてみました。
switch
文で break
を省略すると fallthrough になる言語
- C
- C++
- JavaScript
- PHP
switch
文で break
を省略すると怒られる言語
- C#
-
case
文の中で何もしない場合は、break
を省略できる。 -
goto
で fallthrough のようなことはできる。
-
switch
文で明示的に fallthrough を指定する言語
- Perl (
next
を指定) - Swift (
fallthrough
を指定) - Go (
fallthrough
を指定)
switch
文に近い構文はあるが、 fallthrough はできない言語
- Ruby (
case
文) - Scala (
match
文) - Kotlin (
when
文)
switch
文に相当する構文がない言語
- Python
条件を満たす全てのブロックが実行される言語
- PowerShell
- fall through はできない。
- 条件を満たす全てのブロックが実行される。
-
break
を使えば、打ち切ることができる。
言語によって色々ですね!勉強になりました。