switchcase

switchは、式の値を複数の値と比較する文だ。これは、"if、else if、else"の連鎖と似ているが、同じではない。caseは、switchの式と比較する値を指定するために使う。caseは、switch文の一部であり、文そのものではない。

switchは、括弧で囲まれた式を取り、その式の値をcaseの値と比較し、式の値と等しいcaseの操作を実行する。その構文は、1つ以上のcaseセクションと defaultセクションを含むswitchブロックで構成される。

switch (expression) {

case value_1:
    // 式がvalue_1と等しい場合に実行する操作
    // ...
    break;

case value_2:
    // 式がvalue_2と等しい場合に実行する操作
    // ...
    break;

// ... その他の場合 ...

default:
    // 式がどのケースとも等しくない場合に実行する操作
    // ...
    break;
}
D

switchが取る式は、論理式として直接使用されるわけではない。if文のように"この条件が真の場合"として評価されるわけではない。switch式の値はcase値との等価比較に使用される。これは、等価比較のみを行う"if、else if、else"の連鎖に似ている。

auto value = expression;

if (value == value_1) {
    // value_1に対する操作
    // ...

} else if (value == value_2) {
    // value_2に対する操作
    // ...
}

// ... 他の'else if' ...

} else {
    // 他の値に対する操作
    // ...
}
D

ただし、上記の"if、else if、else"は、switch文とまったく同じではない。その理由は、次のセクションで説明する。

caseの値がswitch式の値と一致する場合、caseの下にある操作が実行される。一致する値がない場合、defaultの下にある操作が実行される。

goto

gotoの使用は、ほとんどのプログラミング言語では一般的に推奨されてない。ただし、gotoは、他の用途ほど問題にならない、switch文では、状況によっては有用だ。goto文については、後の章で詳しく説明する。

caseは、if文のようにスコープを導入しない。ifまたはelseスコープ内の操作が終了すると、if文全体の評価も終了する。これは、caseセクションでは起こらない。一致するcaseが見つかったら、プログラムの実行はそのcaseにジャンプし、その下の操作を実行する。まれな状況で必要な場合、goto caseはプログラムの実行を次のcaseにジャンプさせる。

switch (value) {

case 5:
    writeln("five");
    goto case;    // 次のcaseに進む

case 4:
    writeln("four");
    break;

default:
    writeln("unknown");
    break;
}
D

valueが5の場合、case 5行の下で実行が続き、プログラムは"five"を出力する。その後、goto case文により、実行は次のcaseに進み、その結果、"four"も出力される。

five
four

goto caseセクションでは、3つの方法で現れる可能性がある:

次のプログラムは、foreachループを利用して、これらの3つの使用方法を示している。

import std.stdio;

void main() {
    foreach (value; [ 1, 2, 3, 10, 20 ]) {
        writefln("--- value: %s ---", value);

        switch (value) {

        case 1:
            writeln("case 1");
            goto case;

        case 2:
            writeln("case 2");
            goto case 10;

        case 3:
            writeln("case 3");
            goto default;

        case 10:
            writeln("case 10");
            break;

        default:
            writeln("default");
            break;
        }
    }
}
D
switch_case.1

出力:

switch
1case 1
case 2
case 10
2case 2
case 10
3case 3
default
10case 10
20default
式は、整数、文字列、またはbool型でなければならない。

if文の等価比較では、あらゆる型を使用できる。一方、switch式の型は、すべての整数型、すべての文字列型、およびboolに限定される。

string op = /* ... */;
// ...
switch (op) {

case "add":
    result = first + second;
    break;

case "subtract":
    result = first - second;
    break;

case "multiply":
    result = first * second;
    break;

case "divide":
    result = first / second;
    break;

default:
    throw new Exception(format("Unknown operation: %s", op));
}
D

注釈:上記のコードは、操作がプログラムによって認識されない場合に例外をスローする。例外については、後の章で説明する。

bool式も使用することは可能だが、boolには2つの値しかないので、その型にはif文または三項演算子(?:)を使用するほうが適しているかもしれない。

値の範囲

値の範囲は、caseの間に..で指定できる。

switch (dieValue) {

case 1:
    writeln("You won");
    break;

case 2: .. case 5:
    writeln("It's a draw");
    break;

case 6:
    writeln("I won");
    break;

default:
    /* プログラムはここには到達しないはずである。
     * なぜなら、上記のcaseが有効なdieの値のすべての範囲をカバーしているからである。
     * (以下の'final switch'を参照。) */
    break;
}
D

上記のコードは、サイコロの値が 2、3、4、または5の場合にゲームが引き分けで終了することを決定する。

異なる値

値[2, 5]の範囲にある値ではなく、値2と4が引き分けであると仮定しよう。caseの異なる値は、コンマで区切る。

case 2, 4:
    writeln("It's a draw");
    break;
D
final switch

final switch文は、通常のswitch文とよく似ているが、以下の点が異なる。

int dieValue = 1;

final switch (dieValue) {

case 1:
    writeln("You won");
    break;

case 2, 3, 4, 5:
    writeln("It's a draw");
    break;

case 6:
    writeln("I won");
    break;
}
D
いつ使用する

switchは、式値をコンパイル時に既知の値のセットと比較するのに適している。

比較する値が2つしかない場合は、if文の方がより適切だ。例えば、表か裏かをチェックするには、次のようにする。

if (headsTailsResult == heads) {
    // ...

} else {
    // ...
}
D

原則として、比較する値が3つ以上ある場合は、switchの方が適している。

すべての値を処理する必要がある場合は、final switchを使用することをお勧めする。これは、enum型の場合に特に当てはまる。

演習
  1. 算術演算をサポートする計算機プログラムを作成しよう。プログラムは、まず演算をstringとして読み込み、次に2つの値をdouble型として入力から読み込む。計算機は演算の結果を出力する。例えば、演算と値がそれぞれ"add"と"5 7"の場合、プログラムは12を出力する。

    入力は、以下のコードのように読み込むことができる。

    string op;
    double first;
    double second;
    
    // ...
    
    op = strip(readln());
    readf(" %s %s", &first, &second);
    D
  2. "add"のような単語に加えて"+"のような演算子もサポートするように計算機を改善しよう。
  3. 未知の演算子については、プログラムが例外をスローするようにしよう。例外については、後の章で説明する。とりあえずは、上記のthrow文をプログラムに適用しよう。