在Go中,switch语法非常灵活。

Go 的 switch 语句类似于 C、C++、Java、JavaScript 和 PHP 中的,不过 Go 只运行选定的 case,而非之后所有的 case。实际上,Go自动提供了每个 case 后面所需的 break 语句。 除非以fallthrough语句结束,否则分支会自动终止。 Go 的另一个重要特点在于 switch 的 case 无需为常量,且取值不必为整数。

一 基本的switch语句

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.\n", os)
    }
}

二 switch 的求值顺序

switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。

例如:

switch i {
case 0:
case f():
}

在 i==0 时 f 不会被调用。

三 没有条件的 switch

没有条件的 switch 同 switch true 一样。这种形式能将一长串的if-then-else写得更加清晰,而且这也是Go的惯用语法。
示例1:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("上午好。")
    case t.Hour() < 17:
        fmt.Println("下午好。")
    default:
        fmt.Println("晚上好。")
    }
}
注:与本地不同,Go 练习场中的时间总是从 2009-11-10 23:00:00 UTC 开始。

示例2:

package main

import (
    "fmt"
)

func main() {
    fmt.Println(unhex('c'))
    fmt.Println(unhex('a'))
}

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
}

四 多个条件和标签

4.1 匹配多个条件

case语句不能直接跳过,但是可以将多个条件放在一个case中,用逗号隔开:

package main

import "fmt"

func main() {
    fmt.Println(shouldEscape('c'))
    fmt.Println(shouldEscape(' '))
}

func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+', '%':
        return true
    }
    return false
}

类比:
在Java中,可以这样写:

case "a":
case "b":
case "c":
    return true;
    break;
    ...

4.2 提前终止

break语句可用于提前终止switch。有时候,需要中断外层循环,而不是当前的switch,在Go中,这可以通过在循环上放置一个标签,并中断那个标签来实现:

package main

import "fmt"

func main() {
    array := [6]int{1, 3, 5, 7, 9, 11}

    fmt.Println(array)

Loop:
    for n := 0; n < len(array); n++ {
        //fmt.Println("n =",n)
        switch {
        case array[n] < 5:
            fmt.Printf("array[%v]=%v\n", n, array[n])
            if n < 2 {
                break
            }
        case array[n] < 10:
            if n+1 <= len(array) {
                fmt.Printf("array[%v]=%v,停止Loop标签\n", n, array[n])
                break Loop
            }

        }
    }
}
同样,continue语句也支持这种用法,接受可选的标签,但只限于在循环中使用。

五 类型选择

switch还可用于判断接口变量的动态类型,这种类型选择使用类型断言语法,在括号中使用一个type关键字。如果switch在表达式中声明了一个变量,则该变量在每个子句中都有相应的类型。这种情况下,复用名称也是惯用做法:实际声明了一个具有相同名称但在每种情况下具有不同类型的新变量。

package main

import "fmt"

func main() {
    var value interface{} // Value provided by caller.
    switch str := value.(type) {
    case string:
        fmt.Println(str)
    case Stringer:
        fmt.Println(str.String())
    }

}

type Stringer interface {
    String() string
}

关于类型选择的更多信息,会在后续文章中介绍。

参考:
https://golang.org/doc/effective_go.html#switch
https://golang.org/ref/spec#Switch_statements

文章目录