143

私が覚えている限り、switch ステートメントのフォールスルーを使用することは避けてきました。実は、switch ステートメントのバグにすぎないということは早い段階で頭に突き刺されていたので、それが可能な方法として意識に入った覚えはありません。しかし、今日、意図的にそれを使用するコードに出くわしたので、コミュニティの誰もが switch ステートメントのフォールスルーについてどう考えているのかすぐに気になりました。

それはプログラミング言語が明示的に許可すべきではないものですか (C# のように、回避策は提供されます)、それともプログラマーの手に委ねるほど強力な言語の機能ですか?

編集: フォールスルーの意味が十分に具体的ではありませんでした。私はこのタイプをよく使います:

    switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

とはいえ、こんなのが気になります。

   switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something, but fall through to the other cases
            // after doing it.

        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

このように、case が 0、1 のときはいつでも、switch ステートメントですべてを実行します。私はこれを設計上見てきましたが、switch ステートメントをこのように使用することに同意するかどうかはわかりません。最初のコード例は非常に便利で安全だと思います。2番目はちょっと危険なようです。

4

12 に答える 12

106

それは、フォールスルーと見なすものに依存する場合があります。私はこの種のもので大丈夫です:

switch (value)
{
  case 0:
    result = ZERO_DIGIT;
    break;

  case 1:
  case 3:
  case 5:
  case 7:
  case 9:
     result = ODD_DIGIT;
     break;

  case 2:
  case 4:
  case 6:
  case 8:
     result = EVEN_DIGIT;
     break;
}

しかし、ケース ラベルの後に別のケース ラベルにフォールスルーするコードがある場合、私はほとんど常にそれを悪だと考えています。おそらく、共通コードを関数に移動し、両方の場所から呼び出すことをお勧めします。

そして、 「悪」のC++ FAQ定義を使用していることに注意してください。

于 2008-10-09T18:18:45.440 に答える
61

両刃の剣です。非常に便利な場合もありますが、危険な場合もあります。

いつがいい?10 ケースをすべて同じ方法で処理したい場合は...

switch (c) {
  case 1:
  case 2:
            ... Do some of the work ...
            /* FALLTHROUGH */
  case 17:
            ... Do something ...
            break;
  case 5:
  case 43:
            ... Do something else ...
            break;
}

私が気に入っているルールの 1 つは、ブレークを除外して派手なことをした場合は、それがあなたの意図であることを示す明確なコメント /* FALLTHROUGH */ が必要だということです。

于 2008-10-09T18:17:18.360 に答える
24

ダフのデバイスについて聞いたことがありますか? これは、スイッチ フォールスルーを使用した好例です。

ほとんどすべての言語機能と同様に、これは使用できる機能であり、悪用される可能性があります。

于 2008-10-09T18:16:11.827 に答える
21

フォールスルーは、何をしているかにもよりますが、本当に便利です。オプションを整理するためのこのきちんとしたわかりやすい方法を検討してください。

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // Do something
    break;

  case 'd':
  case 'e':
    // Do something else
    break;
}

if/else でこれを行うことを想像してみてください。それは混乱でしょう。

于 2008-10-09T18:14:40.207 に答える
10

これは数回非常に役立つ場合がありますが、一般的に、フォールスルーは望ましい動作ではありません。フォールスルーは許可する必要がありますが、暗黙的ではありません。

例として、一部のデータの古いバージョンを更新するには、次のようにします。

switch (version) {
    case 1:
        // Update some stuff
    case 2:
        // Update more stuff
    case 3:
        // Update even more stuff
    case 4:
        // And so on
}
于 2008-10-09T19:36:00.197 に答える
6

スイッチのフォールバックには別の構文が必要です。たとえば、エラー..

switch(myParam)
{
  case 0 or 1 or 2:
    // Do something;
    break;
  case 3 or 4:
    // Do something else;
    break;
}

注:これは、フラグを使用して列挙型ですべてのケースを宣言する場合、列挙型ですでに可能ですよね? それほど悪くはありません。ケースはすでに列挙型の一部である可能性があります(すべきですか?)。

多分これは、拡張メソッドを使用した流暢なインターフェースの良いケース (しゃれは意図されていません) でしょうか? エラー...

int value = 10;
value.Switch()
  .Case(() => { /* Do something; */ }, new {0, 1, 2})
  .Case(() => { /* Do something else */ } new {3, 4})
  .Default(() => { /* Do the default case; */ });

それはおそらくさらに読みにくいですが:P

于 2009-02-10T00:02:25.350 に答える
4

強力で危険です。フォールスルーの最大の問題は、それが明示的でないことです。たとえば、頻繁に編集され、フォールスルーを伴うスイッチがあるコードに遭遇した場合、それがバグではなく意図的なものであるとどのように判断できるでしょうか?

どこで使用しても、適切にコメントされていることを確認します。

switch($var) {
    case 'first':
        // Fall-through
    case 'second':
        i++;
        break;
 }
于 2008-10-09T18:15:52.030 に答える
4

何でもそうですが、注意して使えばエレガントなツールになります。

ただし、欠点はそれを使用しないことを正当化する以上のものであり、最終的にはもう使用できないと思います (C#)。問題の中には次のものがあります。

  • 休憩を「忘れる」のは簡単です
  • コード管理者にとって、省略されたブレークが意図的であったことが常に明らかであるとは限りません

スイッチ/ケース フォールスルーの適切な使用:

switch (x)
{
case 1:
case 2:
case 3:
 Do something
 break;
}

スイッチ/ケースフォールスルーのばかげた使用:

switch (x)
{
case 1:
    Some code
case 2:
    Some more code
case 3:
    Even more code
    break;
}

私の意見では、これは if/else 構造を使用してまったく損失なく書き直すことができます。

最後に、このスタイルが使用され、十分に理解されているレガシー コードを維持している場合を除き、悪い例のようにフォールスルー ケース ラベルを使用しないでください。

于 2008-10-09T18:17:16.440 に答える
3

最初の例のようにフォールスルーを使用することは明らかに問題ありません。実際のフォールスルーとは考えません。

2 番目の例は危険であり、(広範囲にコメントしない限り) 自明ではありません。私は生徒たちに、これが意図的なフォールスルーであり、なぜこの解決策が代替案よりも優れているのかを説明するコメント ブロックをそれに割く努力する価値があると考えない限り、そのような構成要素を使用しないように教えています。これは、ずさんな使用を思いとどまらせますが、有利に使用される場合には許容されます。

これは、誰かがコーディング標準に違反したいときに宇宙プロジェクトで行ったこととほぼ同じです。彼らは免除を申請しなければなりませんでした (そして、私はその裁定について助言するよう求められました)。

于 2011-09-10T21:07:43.357 に答える
2

switch私は自分のステートメントが失敗するのが好きではありません。エラーが発生しやすく、読みにくいからです。唯一の例外は、複数のcaseステートメントがすべてまったく同じことを行う場合です。

switch ステートメントの複数のブランチで使用したい共通コードがある場合は、それを抽出して、任意のブランチで呼び出すことができる別の共通関数にします。

于 2008-10-09T18:17:58.157 に答える
1

フォールスルーは、コード ブロックへのジャンプ テーブルとして使用する場合にのみ使用してください。次のケースの前に無条件のブレークがあるコードの部分がある場合、すべてのケース グループはそのように終了する必要があります。

それ以外は「悪」です。

于 2009-02-09T23:07:12.220 に答える
1

場合によっては、フォールスルーを使用することは、プログラマー側の怠惰な行為です。一連の || を使用できます。たとえば、ステートメントを使用しますが、代わりに一連の「キャッチオール」スイッチ ケースを使用します。

そうは言っても、最終的にオプションが必要になることがわかっている場合(たとえば、メニュー応答など)、まだすべての選択肢を実装していない場合、それらが特に役立つことがわかりました。同様に、'a' と 'A' の両方に対してフォールスルーを行っている場合、複合 if ステートメントよりもスイッチ フォールスルーを使用する方が実質的にクリーンであることがわかります。

それはおそらくスタイルとプログラマーの考え方の問題ですが、私は一般的に「安全」の名の下に言語のコンポーネントを削除するのが好きではありません.ジャバ。「理由」がなくても、ポインターなどを使って猿回しできるのが好きです。

于 2008-10-09T18:16:54.350 に答える