Go公式WikiのSwitchの日本語意訳になります。
(元記事の最終更新日: 2017/05/31 rev.7)
スイッチ文に関する簡単な説明がされています。
Switch
仕様: https://golang.org/ref/spec#Switch_statements
Go言語のswitch
文は非常にきれいです。一例として、各ケースの最後にbreak
をする必要がありません。
// 訳注: HTMLの特殊文字のエスケープを行っている
switch c {
case '&':
esc = "&"
case '\'':
esc = "'"
case '<':
esc = "<"
case '>':
esc = ">"
case '"':
esc = """
default:
panic("unrecognized escape character")
}
int型以外の型もOK
スイッチはどのような型の値でも扱うことができます。
// 訳注: OSごとに異なるシステムディレクトリを取得
// (下記URLの処理から抜粋していると思われる)
// https://golang.org/src/os/os_test.go#L72
switch syscall.OS {
case "windows":
sd = &sysDir{
Getenv("SystemRoot") + `\system32\drivers\etc`,
[]string{
"hosts",
"networks",
"protocol",
"services",
},
}
case "plan9":
sd = &sysDir{
"/lib/ndb",
[]string{
"common",
"local",
},
}
default:
sd = &sysDir{
"/etc",
[]string{
"group",
"hosts",
"passwd",
},
}
}
式無しでもswitch可能
何かをスイッチする必要は全くありません。値なしでのスイッチは “switch true
” を意味しています。
下記のEffective Goでの例のように、より洗練された 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
}
ブレーク
Goのswitch
文は暗黙のbreak
をしています。
しかし、明示的なbreak
はそれでも便利です。
// 訳注: コマンドとなる文字列を受け取り、そのコマンドに合わせて処理を実行する
command := ReadCommand()
argv := strings.Fields(command)
switch argv[0] {
case "echo":
fmt.Print(argv[1:]...)
case "cat":
if len(argv) <= 1 {
fmt.Println("Usage: cat <filename>")
break // 訳注: 明示的なbreak
}
PrintFile(argv[1])
default:
fmt.Println("Unknown command; try 'echo' or 'cat'")
}
フォールスルー
次のケースにフォールスルーして進むには、 fallthrough
キーワードを使います。
// バイト文字列に対して、4バイトをuint32へとunpackし、base85形式の5バイトへと再度packする
var v uint32
switch len(src) {
default:
v |= uint32(src[3])
fallthrough
case 3:
v |= uint32(src[2]) << 8
fallthrough
case 2:
v |= uint32(src[1]) << 16
fallthrough
case 1:
v |= uint32(src[0]) << 24
}
訳注: Go PlayGroundで確認
‘fallthrough
’ はケースの最後に書く必要があります。
以下のような書き方はできません。
switch {
case f():
if g() {
fallthrough // これは動かない!(コンパイルエラー)
}
h()
default:
error()
}
しかし、この問題を回避して動かすには「ラベル付き」の fallthrough
を使います。
switch {
case f():
if g() {
goto nextCase // これで動く!
}
h()
break
nextCase:
fallthrough
default:
error()
}
複数のケース
複数の値を同じケースとして扱いたい場合には、カンマ区切りのリストを使います。
func letterOp(code int) bool {
switch chars[code].category {
case "Lu", "Ll", "Lt", "Lm", "Lo":
return true
}
return false
}
// 訳注: もし値のリストが長くなる場合は以下のように改行を加えると見やすくなるかもしれません。
switch str {
case "aaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccc",
"dddddddDDDDDDDDDDDDDDDDDDDD",
"eeEEeeEEeeEEeeEEeeEEeeEE":
return true
}
型スイッチ
型スイッチによって、インターフェースの値の実際の型でスイッチすることができます。
func typeName(v interface{}) string {
switch v.(type) {
case int:
return "int"
case string:
return "string"
default:
return "unknown"
}
}
変数を宣言することも可能で、各ケースの型を持った値となります。
func do(v interface{}) string {
switch u := v.(type) {
case int:
return strconv.Itoa(u*2) // このケースでは u はint型
case string:
mid := len(u) / 2 // 分割 - このケースでは u はstring型
return u[mid:] + u[:mid] // 結合
}
return "unknown"
}
do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"
Noopケース
場合によっては何も実行しないケースは便利なこともあります。
これは紛らわしく見える可能性があり、Noopケースとその後のケースが同じ動作をするように見えますが、そうはなりません。
// 訳注: pluralEndingの引数に1を渡した場合は何もせず、
// それ以外のintを渡した場合は英単語の複数形となる s を返却する
func pluralEnding(n int) string {
ending := ""
switch n {
case 1:
default:
ending = "s"
}
return ending
}
fmt.Sprintf("foo%s\n", pluralEnding(1)) == "foo"
fmt.Sprintf("bar%s\n", pluralEnding(2)) == "bars"
comments powered by Disqus