Go switch 文
Go 言語において、switch 文は複数の条件分岐を処理するためのクリーンかつ効率的な方法を提供します。長い if-else if-else ステートメントと比較して、switch 文は特に多くの条件判断が必要な場合に、コードの可読性と保守性を劇的に向上させます。
基本的なコントロールフロー構造として、変数や式の値に基づいて異なるコードブロックを実行することができます。
本章では、Go 言語における switch 文の構文、機能的な特徴、そして様々な実用的なユースケースについて深く掘り下げていきます。
1. switch 文の基本
最も基本的な switch 文は、式の値を一連の候補値と比較します。各候補値は case 節に関連付けられており、マッチングに成功すると、その case の下のコードブロックが実行されます。
1.1 基本構文
switch 文の一般的な構文は以下の通りです:
switch expression {
case value1:
// expression == value1 の場合に実行されるコード
case value2:
// expression == value2 の場合に実行されるコード
...
default:
// 上記のどの case にもマッチしない場合に実行されるコード
}- expression (式): 評価される式です。変数、関数呼び出し、または任意の有効な Go の式を指定できます。
- case value: 各
case節は一つの値を指定し、expressionの結果と比較します。マッチした場合、そのcase以降のコードが実行されます。 - default:
defaultブランチはオプションです。存在する場合、どのcaseにもマッチしなかったときに実行されます(if-elseにおけるelseと同様です)。
1.2 コード例
package main
import "fmt"
func main() {
grade := "B"
switch grade {
case "A":
fmt.Println("優秀!")
case "B":
fmt.Println("よくできました!")
case "C":
fmt.Println("合格。")
case "D":
fmt.Println("改善が必要です。")
case "F":
fmt.Println("不合格。")
default:
fmt.Println("無効な成績です。")
}
}この例では、switch 文が変数 grade の値を判断します。grade が "B" であるため、プログラムは case "B": の下のコードを実行し、コンソールに「よくできました!」と出力します。もし grade がどのアルファベットにもマッチしない場合は、default ブランチが実行され、「無効な成績です。」と出力されます。
1.3 break 文の省略
C、C++、Java などの言語を学んだことがある方は、各 case の末尾にコードのフォールスルー(次の case への流出)を防ぐために break を書く習慣があるかもしれません。
Go 言語では break を書く必要はありません。 Go の switch 文は、最初にマッチした case ブロックを実行した後、自動的に switch 構造全体を抜けます。もし意図的に次の case へ処理を継続させたい場合は、明示的に fallthrough キーワードを使用する必要があります(詳細は後述します)。
2. 複数の値とのマッチング
Go 言語では、一つの case に複数のマッチング値をカンマ , 区切りで含めることができます。これにより、似たような状況を簡単に一つのグループにまとめることができます。
2.1 構文と実例
switch expression {
case value1, value2, value3:
// expression が value1、value2、または value3 のいずれかであれば実行
...
}平日と週末を判定する例を見てみましょう:
package main
import "fmt"
func main() {
day := "Wed" // 水曜日
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
fmt.Println("今日は平日です。")
case "Sat", "Sun":
fmt.Println("今日は週末です!")
default:
fmt.Println("無効な日付です。")
}
}ここでは、day の値が "Mon" から "Fri" のいずれかであれば、「今日は平日です。」と出力されます。
3. 式のない switch
Go の switch 文は、式を伴わずに記述することも可能です。この場合、各 case 節をブール値 (true または false) を返す条件判断として記述できます。プログラムは上から下へ計算し、最初に結果が true になった case を実行します。
これは実質的に、非常にエレガントに記述できる if-else if-else チェーンとなります。
3.1 構文と実例
switch {
case condition1:
// condition1 が true の場合に実行
case condition2:
// condition2 が true の場合に実行
...
default:
// 上記の条件がすべて true でない場合に実行
}年齢に基づいて層を分ける例を見てみましょう:
package main
import "fmt"
func main() {
age := 25
// 注意:switch の後に式がない
switch {
case age < 13:
fmt.Println("子供")
case age >= 13 && age < 20:
fmt.Println("青少年")
case age >= 20 && age < 65:
fmt.Println("成人")
default:
fmt.Println("高齢者")
}
}age が 25 なので、最初に true と評価される条件は age >= 20 && age < 65 となり、「成人」と出力されます。
4. fallthrough 穿透(フォールスルー)文
fallthrough キーワードは、次の case の条件がマッチするかどうかにかかわらず、強制的に次の case のコードブロックを実行させるために使用されます。これは Go のデフォルトである「マッチしたら終了」というルールを打破します。
4.1 実例によるデモンストレーション
package main
import "fmt"
func main() {
number := 2
switch number {
case 1:
fmt.Println("一")
case 2:
fmt.Println("二")
fallthrough // フォールスルーをトリガー!
case 3:
fmt.Println("三")
default:
fmt.Println("その他")
}
}number が 2 の時、上記のコードの出力結果は以下のようになります:
二
三何が起きたのでしょうか? プログラムは case 2 にマッチし、「二」を出力しました。直後に fallthrough に遭遇したため、プログラムは強制的に隣接する case 3 のコードブロックに「蹴り込まれ」、number が実際には 3 でないことを完全に無視して「三」を出力しました。
注意:fallthrough は慎重に使用してください。乱用するとコードのロジックが極めて理解しにくくなる可能性があります。
5. 型スイッチ (Type switch)
型スイッチ (Type switch) は非常に特殊な switch 文で、変数の「値」ではなく、変数の「データ型」を判定します。
これは、実行時に様々な異なる低レイヤーの型の値を保持できる インターフェース (Interface) 型を処理する際に非常に有用です。
5.1 構文と実例
switch v := interfaceValue.(type) {
case type1:
// この時、v の型は type1
case type2:
// この時、v の型は type2
...
default:
// どれにもマッチしない場合
}- interfaceValue: 実際の型を確認したいインターフェース変数。
- v := interfaceValue.(type): これは型アサーションの特殊な構文です。型を判定するだけでなく、低レイヤーの実際の値を新しい変数
vに代入し、vは自動的にマッチした型になります。
package main
import "fmt"
// 空のインターフェースを受け取る。つまり、あらゆる型の値を渡せる
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("これは整数です: %d\n", v)
case string:
fmt.Printf("これは文字列です: %s\n", v)
case bool:
fmt.Printf("これはブール値です: %t\n", v)
default:
fmt.Printf("未知の型です\n")
}
}
func main() {
describe(10)
describe("Hello")
describe(true)
}この例では、describe 関数内の型スイッチが渡された値の低レイヤーの型を正確に識別し、対応する出力を生成しています。