switch は1つの値をcaseのリストと比べ、最初に一致したものを実行します。C、Java、JavaScriptと違って、Goのcaseは次のcaseに フォールスルーしない ので、break を書き忘れることもありません。
caseは上から下へチェックされ、最初に一致したcaseだけが実行されます。default は何も一致しないときに実行されます。省略でき、リストのどこに置いても構いませんが、慣習では最後に置きます。
caseごとの複数の値
case "sat", "sun": はどちらの値にも一致します。Cが空のcaseを積み重ねて表すことを、Goはこう書きます。比較可能な型なら何でも使えます。文字列、数値、ルーン、真偽値、ポインタ、そして列挙型のような名前付きの型です。
同じ定数値を持つ2つのcaseはコンパイルエラーになります。
./main.go:10:7: duplicate case 1 (constant of type int) in expression switch
./main.go:8:7: previous case
条件のないswitch
式を省略すると、各caseが真偽値のテストになります。これは長い if/else if の連鎖を、Goでよりすっきり書いた形です。
switch { は switch true { の省略形です。最初に真になったcaseが勝つので、順序が重要です。bmi < 25 に到達するのは bmi < 18.5 が偽だったときだけなので、各caseは上のcaseが失敗したことを前提にできます。
初期化文付きのswitch
if と同じく、switch も短い文から始められます。そこで宣言した変数のスコープはswitchの中だけです。
初期化文は条件のないswitchと組み合わせることもできます:switch n := len(items); { case n == 0: ... }。
fallthrough
次のcaseに実行を続けたいときは、caseの最後の文として fallthrough を書きます。これは 条件を評価せずに 次のcaseの本体に制御を移します。
レベル2では write の次に read が表示され、権限が下に向かって積み重なります。後のcaseの条件はチェックされません。case 2 から fallthrough した後は、level が2であっても case 1 が実行されます。
fallthrough のルールは次のとおりです。
- caseの最後の文でなければならない。
- 最後のcaseには書けない:
cannot fallthrough final case in switch。 - 型スイッチでは使えない。
実際のGoのコードで fallthrough を見ることはまれです。caseごとの複数の値でよくある用途はまかなえますし、fallthroughの連鎖より明示的な関数呼び出しのほうがたいてい明快です。
switchの中のbreak
case内の break は switch を抜けます。caseは自然に終わるので、必要になるのはcaseを途中で抜けるときだけです。罠になるのは、ループの中の switch です。
loop ラベルがないと、break はswitchを終わらせるだけで、ループは "c" へと続きます。一方 continue は、switch がループではないので、常に外側のループを指します。
型によるswitch
型スイッチは、特別な形 v.(type) を使って、インターフェースの値の動的な型で分岐します。
型が1つだけのcaseでは、x はその型になります(string のcaseでは len(x) が使えます)。複数の型を並べたcaseでは、x はインターフェース型のままです。型スイッチと v.(T) のアサーションは型アサーションのページで詳しく扱っています。
Goのswitchが違うところ
| 挙動 | C、Java、JavaScript | Go |
|---|---|---|
| 次のcaseへの流れ込み | デフォルト | fallthrough のときだけ |
各caseの最後の break | 必須 | 不要 |
| caseごとの複数の値 | 空のcaseを積み重ねる | case a, b, c: |
| caseの値 | (ほとんど)定数 | 任意の式、上から順に評価 |
| switchの値 | 整数型(C) | 比較可能な任意の型 |
| switchの式がない | 使えない | switch { case cond: } |
caseの式は定数である必要はありません。case limit(), max + 1: も正しいコードです。一致するまで順に評価されるので、後ろの式は一度も実行されないこともあります。
網羅性
Goは、列挙型に対するswitchがすべての値を網羅しているかをチェックしません。想定外の値に対してログを出す、エラーを返す、またはpanicする default を加えるか、exhaustive リンター(golangci-lint の一部)を使って、漏れたcaseをビルド時に報告させます。
よくある質問
Goのswitchは次のcaseにフォールスルーしますか?
しません。Goのcaseは次の case のところで自動的に終わり、止めるために break を書くことはありません。次のcaseの本体に実行を続けたい場合は、caseの最後の文として fallthrough を書きます。これは次のcaseの条件をチェックせずに無条件でジャンプします。
Goで1つのcaseに複数の値をマッチさせるには?
カンマで区切って並べます:case "sat", "sun":。switchの値がそのどれかと等しければ、そのcaseが実行されます。CやJavaで空のcaseを積み重ねていた書き方の代わりになります。
Goの条件のないswitchとは何ですか?
switch { case x < 0: ...; case x == 0: ...; default: ... } です。switch の後に式がないと、各caseは真偽値の条件になり、最初に真になったものが実行されます。長い if/else if の連鎖の代わりとなるGoらしい書き方です。
Goのswitchの中のbreakは何をしますか?
外側の for ループではなく switch を終わらせます。caseは自然に終わるのでめったに必要ありませんが、ループ内のswitchで break を書いてループを抜けられると思った人は驚きます。ループを抜けるには、ラベル付きの break か return を使います。