Go 言語の switch 文は、Java や C++ に比べて簡潔に記述できるようになっています。
switch 文の基本
Go 言語の switch 文では、case に複数の値をカンマで区切って指定することができます。
1つの case が実行されると自動的に switch 文を終了するため、C 言語のように case ごとに break と記述する必要はありません。
逆に、次の case を続けて実行したい場合は、明示的に fallthrough と記述する必要があります。
func checkNumber(i int) {
switch i {
case 0:
fmt.Println("zero")
case 2, 3, 5, 7:
fmt.Println("primary number")
fallthrough
default:
fmt.Println("good number")
}
}
if 文の代わりに switch 文を使うことでコードを簡潔にできることがあります。
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
if 文と同様に、switch 文でも変数のスコープをブロック内に絞った変数定義を行うことができます。
次の os 変数は、switch 文の中でのみ参照できます。
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS = OS X")
case "linux":
fmt.Println("OS = Linux")
default:
// freebsd, openbsd, plan9, windows...
fmt.Printf("OS = %s\n", os)
}
連続する if else の代わりとして switch 文を使用する
switch 文の条件部分を省略 すると、switch true と記述するのと同様の振る舞いをします。
この記述方法は、連続した if else を簡潔に記述するために使用することができます。
典型的なのは、ある変数の値を大小比較したいケースです。
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
もう 1 つ例を。
func greet() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning.")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
上記の変数 t のスコープを switch 文の内部に絞りたいのであれば、下記のように変数定義します(セミコロンの後ろの条件部分だけを省略します)。
switch t := time.Now(); {
case t.Hour() < 12:
fmt.Println("Good morning.")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
ちなみに上記の switch を if else を使って書き換えると次のようになります。
if t := time.Now(); t.Hour() < 12 {
fmt.Println("Good morning!")
} else if t.Hour() < 17 {
fmt.Println("Good afternoon.")
} else {
fmt.Println("Good evening.")
}
まぁ、このくらいであればそれほど差はありませんが、それでも switch の方が可読性は高そうです。
型スイッチ (Type Switch)
Go 言語の関数で任意の型の引数を受け取るには、空インタフェース型 interface{} を使用します。 オブジェクトの実際の型に基づいて分岐処理を行うには、次のように 型スイッチ (Type Switch) の仕組みを使います。
func checkType(value interface{}) {
switch v := value.(type) {
case nil:
fmt.Println("value is nil")
case int:
fmt.Printf("value is int (%d)\n", v)
case float64:
fmt.Printf("value is float64 (%f)\n", v)
case func(int) string:
fmt.Println("value is function that takes int and returns string")
case bool, string:
fmt.Println("value is bool or string")
default:
fmt.Printf("value has unknown type (%T)\n", v)
}
}
上記の例では、value 変数の実際の型によって分岐処理を行っています。
さらに、分岐後は v 変数をその型の値として参照することができます。
型スイッチは、型アサーション (Type Assertion) の特殊形態だと考えることができます。