多くの場合、switchステートメントについて聞くと、長いif ... elseチェーンを置き換える方法として延期されます。しかし、switchステートメントを使用するときは、他のコードを記述しているように見えます。 同じスコープ内のすべての呼び出しのすべての変数を保持する などの他の問題もあります。
これは、私が通常書くフローを表すコードです( thanks to diam )
String comment; // The generated insult.
int which = (int)(Math.random() * 3); // Result is 0, 1, or 2.
if (which == 0) {
comment = "You look so much better than usual.";
} else if (which == 1) {
comment = "Your work is up to its usual standards.";
} else if (which == 2) {
comment = "You're quite competent for so little experience.";
} else {
comment = "Oops -- something is wrong with this code.";
}
それから彼らは私にそれをこれで置き換えることを望みます:
String comment; // The generated insult.
int which = (int)(Math.random() * 3); // Result is 0, 1, or 2.
switch (which) {
case 0:
comment = "You look so much better than usual.";
break;
case 1:
comment = "Your work is up to its usual standards.";
break;
case 2:
comment = "You're quite competent for so little experience.";
break;
default:
comment = "Oops -- something is wrong with this code.";
}
かなり厄介な構文では、はるかに多くのコードのようです。しかし、switchステートメントを使用することには本当に利点がありますか?
この特定の状況では、if
とcase
はどちらも不適切な選択であるように思われます。私は単純な配列を使用します:
String comments[] = {
"You look so much better than usual.",
"Your work is up to its usual standards.",
"You're quite competent for so little experience."
};
String comment = comments[(int)(Math.random() * 3)];
補足として、通常、3
をハードコーディングするのではなく、配列のサイズに基づいて乗数を計算する必要があります。
wouldケース/スイッチを使用する場合については、if
ステートメントのカスケード(または少なくとも1つの大きな違い)との違いは、switch
がセミ値の数と密度に基づいて自動的に最適化しますが、if
ステートメントのカスケードはコンパイラに選択肢をほとんど残さず、一致したものが見つかるまで値を1つずつテストしていきます。実際のケースが3つだけの場合、それはほとんど問題になりませんが、十分な数があると、それは重要な場合があります。
if...else if...
チェーンの問題は、それを読みに来たときに、すべてのif
条件を調べて、プログラムの動作を理解する必要があることです。たとえば、次のようなものがあるとします。
if (a == 1) {
// stuff
} else if (a == 2) {
// stuff
} else if (a == 3) {
// stuff
} else if (b == 1) {
// stuff
} else if (b == 2) {
// stuff
}
(明らかに、このような少数のステートメントについては、それほど悪くはありません)
すべてのステートメントを1つも読み取らずに、途中で条件変数を変更したことを知る方法はありません。ただし、switch
は単一の条件変数のみに制限するため、何が起こっているのかが一目でわかります。
しかし、結局のところ、switch
もif...else if
のチェーンもどちらも好みません。多くの場合、より良い解決策は、元の質問のような場合のジャンプテーブルや辞書のようなもの、または多態性(言語でサポートされている場合)です。もちろん、常に可能とは限りませんが、最初のステップとしてswitch
を回避する解決策を探します...
switch (which) {
case 0: comment = "String 1"; break;
case 1: comment = "String 2"; break;
case 2: comment = "String 3"; break;
default: comment = "Oops"; break;
}
このタイプのスイッチケースを書く上記の方法はかなり一般的です。かさばる場合にスイッチケースを感じた理由は、ボディが1行だけであり、スイッチケースの場合はbreakステートメントも必要だったからです。したがって、スイッチケースのボディサイズは他の場合の2倍でした。より実質的なコードでは、breakステートメントは本体に多くを追加しません。単一行の本体の場合、コードをcaseステートメントと同じ行に記述するのが一般的な方法です。
他の人がすでに述べたように、switch caseは意図をより明確にし、単一の変数/式の値に基づいて決定を下したいとします。私のコメントは純粋に可読性の観点からのものであり、パフォーマンスに基づくものではありません。
この場合、switchステートメントはコードの意図とより明確に一致します。単一の値に基づいて実行するアクションを選択します。
一方、ifステートメントは非常に読みにくくなっています。何が起こっているのかを確認するには、それらすべてを調べる必要があります。私にとっては、精神的に解析する必要が少ないため、コードは少なくなります(たとえ文字数mayが少し高くても)。
この特定のケースでは文字列の配列の方が優れているが、一般的には、elseifのチェーンよりもswitch/caseステートメントを使用する方がよいというジェリーにも同意します。読みやすく、コンパイラーがそのように最適化することでより適切に処理できる場合もありますが、別の利点もあります。デバッグがはるかに簡単です。
そのスイッチを押すと、一度にいくつかのifステートメントを1つずつ注意深くステップオーバーし、キーをあまりにも速く押してそれを通り過ぎて何かを失い、何かを失ってしまう代わりに、1回ステップするだけで正しい分岐にたどり着くだけで済みます。やり直す。
私はそのような場合にスイッチを好む、それはコードのポイントにはるかによくマッチし、異なる入力値ごとに異なるステートメントを実行します。 if..else
は、同じ効果を達成するための「トリック」のように機能します。
switch
ステートメントもすっきりしており、タイプミスを簡単に隠すことができます==
また、Cの大きなブロックの場合、切り替えが速くなります。
else..if
は、範囲(1から100の間、これを行う、100から200の間など)のようなものがある場合、またはCで文字列などの要素を使用してスイッチを作成しようとする場合(他の言語で可能) )。どちらも同じです。
Cでプログラミングするときは、多くのスイッチを使用する傾向があります。
私は一般的にどちらのアプローチも好きではありません。長いスイッチまたはifステートメントは、オブジェクト指向の抽象化にリファクタリングするように頼みます(ただし、私があなたの例を長いものではなく、短いものとして分類します)。
私はそのようなコードを個別のヘルパーメソッドに個人的にラップします。
private string GetInsult()
{
int which = (int)(Math.random() * 3); // Result is 0, 1, or 2.
switch (which) {
case 0: return "You look so much better than usual.";
case 1: return "Your work is up to its usual standards.";
case 2: return "You're quite competent for so little experience.";
default: return "Oops -- something is wrong with this code.";
}
}
public void Foo()
{
string comment = GetInsult();
Print(comment);
}
Switchを別のメソッドに配置すると、returnステートメントをswitchステートメント内に直接(少なくともc#で)配置でき、breakステートメントも不要になり、コードが非常に読みやすくなります。
そして、これはif/else if/else ifアプローチよりもはるかに優れています。
効率的で簡潔なものを選び、次にdocument何をしたかだけでなく、なぜかを選びます。
コードは再検討される可能性があり、常に元の作成者が再作成するわけではありません。
ある実装を別の実装より意図的に選択する場合があります理由存在しないコードについて前向きに考えています。
C/C#スタイルswitch
を特に煩わしくするものの1つは、case
値がリテラルであることの主張です。 VB/VB.NETの良い点の1つは、select/case
を使用すると、各ケースを任意のブール式にすることができます。 それが便利です。相互に排他的なブール式のシリーズが役立つ場合が多い限り、一連のif/else ifsの方がより柔軟であり、タイプと読み取りがより効率的であることは言うまでもありません。
Pythonでは、if/Elif/elseがNiceであるため、switchステートメントはありません。
a = 5
if a==1:
print "do this"
Elif a == 2:
print "do that"
Elif a == 3:
print "do the other"
Elif 3 < a < 9:
print "do more"
Elif 9 <= a < 15:
print "do nothing"
else:
print "say sorry"
シンプルでしょ?