web-dev-qa-db-ja.com

リターンを含むSwitchステートメント-コードの正確さ

ほぼこの構造を持つCのコードがあるとしましょう:

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

今では明らかに、「ブレーク」はコードを正しく実行するために必要ではありませんが、私にそれらをそこに置かなければ、それは一種の悪い習慣のように見えます。

どう思いますか?それらを削除しても大丈夫ですか?または、「正確性」を高めるためにそれらを保持しますか?

78
houbysoft

breakステートメントを削除します。これらは必要ではなく、おそらく一部のコンパイラは"Unreachable code"警告を発行します。

115
kgiannakakis

私は完全に別のタックを取ります。メソッド/関数の途中で戻らないでください。代わりに、戻り値をローカル変数に入れて、最後に送信します。

個人的には、次の方が読みやすいと思います。

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;
27
NotMe

個人的には、返品を取り除いて休憩を取ります。 switchステートメントを使用して、変数に値を割り当てます。次に、switchステートメントの後にその変数を返します。

これは議論の余地のある点ですが、良いデザインとカプセル化は、ある意味での出入りを意味すると常に感じています。ロジックを保証する方がはるかに簡単であり、関数の循環的な複雑さに基づいて、誤ってクリーンアップコードを見逃すことはありません。

例外が1つあります。リソースの取得前に、関数の開始時に不正なパラメーターが検出された場合、早期に戻ることは問題ありません。

8
Amardeep AC9MF

休憩を保持する-休憩が既に設定されている場合、後でコードを編集する場合/後で問題が発生する可能性が低くなります。

そうは言っても、多くの人(私を含む)は関数の途中から戻るのは悪い習慣だと考えています。理想的には、関数には1つの入口点と1つの出口点が必要です。

5
Paul R

それらを削除します。 caseステートメントから戻ることは慣用的であり、そうでない場合は「到達不能コード」ノイズです。

5
Stephen

それらを削除します。私の本では、そのようなデッドコードはエラーとみなされるべきです。ダブルテイクを行い、「その行をどのように実行するでしょうか?」

5
Hank Gay

私は通常、それらなしでコードを書きます。 IMO、デッドコードは、ずさんな、および/または理解不足を示す傾向があります。

もちろん、私は次のようなものも考えます:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

編集:編集された投稿でも、この一般的なアイデアはうまく機能します。

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

ある時点で、特に入力値がスパース(1、100、1000、10000など)の場合、代わりにスパース配列が必要です。これをツリーまたはマップとして適切に実装できます(もちろん、この場合もスイッチは機能します)。

4
Jerry Coffin

どう思いますか?それらを削除しても大丈夫ですか?または、「正確さ」を高めるためにそれらを保持しますか?

それらを削除しても構いません。 returnの使用はexactlybreakを使用すべきではないシナリオです。

2
OscarRyz

それらを削除し、デフォルトのブランチを定義すると言います。

2
Bella

配列を持っている方が良いと思いませんか

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

そして、やります return arr[something];

一般的なプラクティスについては、breakステートメントをスイッチに保持する必要があります。将来returnステートメントが不要になった場合、次のcaseに移行する可能性が低くなります。

2
Vivin Paliath

「正しさ」、単一のエントリ、単一の出口ブロックは良いアイデアです。少なくとも、私がコンピューターサイエンスの学位を取得したときでした。だから私はおそらく変数を宣言し、スイッチでそれを割り当て、関数の終わりに一度返すだろう

2
Steve Sheldon

面白い。これらの答えのほとんどからのコンセンサスは、冗長なbreakステートメントが不要な混乱であるようです。一方、スイッチのbreakステートメントは、ケースの「閉じる」ものとして読みました。 caseで終わっていないbreakブロックは、バグが発生する可能性がありますが、私に飛びつく傾向があります。

returnの代わりにbreakがあるときはそうではないことを知っていますが、それは私の目がスイッチのケースブロックを「読む」方法なので、私は個人的にcasebreakとペアになります。しかし、多くのコンパイラーは、breakの後にreturnが不必要/到達不能であることに文句を言いますが、どうやら私は少数派のようです。

breakに続くreturnを取り除きます。

NB:これはすべて、単一のエントリ/出口ルールに違反することが良いアイデアかどうかを無視しています。それに関しては、残念ながら状況によって変わるという意見があります...

1
Michael Burr

* break * sは目的のためにあると思います。プログラミングの「イデオロギー」を生かし続けるためです。論理的な一貫性を持たずにコードを「プログラム」するだけなら、今は読みやすいかもしれませんが、明日試してみてください。上司に説明してみてください。 Windows 3030で実行してみてください。

ブレ、アイデアは非常に簡単です。


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_Assembly;
   LONG Assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/ *ただし、ちょっとした質問です。上記を読んでいる間、コーヒーはどれくらい飲みましたか?それ。 Breaksシステムは時々* /

0
Cruentos Solum

「ルックアップ」タイプのコードがある場合、switch-case句を単独でメソッドにパッケージ化できます。

楽しみのために開発している「趣味」システムには、これらのいくつかがあります。

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(はい、それはGURPSスペースです...)

ほとんどの場合、メソッドでの複数の戻り値を避ける必要があることを他の人に同意します。これは、配列または他の何かとして実装した方が良いかもしれないことを認識しています。上記のように、switch-case-returnは、入力と出力が1-1の相関関係を持つルックアップテーブルに非常に簡単に一致することがわかりました(ロールプレイングゲームはそれらでいっぱいで、他にも存在するはずです) 「ビジネス」も))D

一方、case-clauseがより複雑な場合、またはswitchステートメントの後に何かが発生した場合、returnを使用することはお勧めしませんが、スイッチに変数を設定し、breakで終了してreturn最後の変数の値。

(...三番目の手...あなたはいつでも独自のメソッドにスイッチをリファクタリングすることができます...私はそれがパフォーマンスに影響を与えることを疑います、そして現代のコンパイラがそれをインライン化できるもの...)

0
Erk

私は個人的にbreaksを失う傾向があります。おそらくこの習慣の原因の1つは、Windowsアプリのウィンドウプロシージャをプログラミングすることです。

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

個人的には、このアプローチは、各ハンドラーによって設定された戻り変数を宣言し、最後に返すよりもはるかに単純で簡潔で柔軟であると思います。このアプローチを考えると、breaksは冗長であり、実行する必要があります-それらは有用な目的(構文上または視覚的にIMO)を提供せず、コードを膨張させるだけです。

0
Mac

ある時点で終了コード。これにより、コードの読みやすさが向上します。間にreturnステートメント(複数の出口)を追加すると、デバッグが困難になります。

0
Clarice

それらを削除すると言います。コードが読めないために「安全のため」にブレークを挿入する必要がある場合は、コーディングスタイルを再検討する必要があります:)

また、私は常にswitchステートメントでブレークとリターンを混在させず、むしろそれらの1つに固執することを好みました。

0
Thomas Kjørnes