使用 switch 语句控制流

已完成

像其他编程语言一样,Go 支持 switch 语句。 可以使用 switch 语句来避免链接多个 if 语句。 使用 switch 语句,就不需维护和读取包含多个 if 语句的代码。 这些语句还可以让复杂的条件更易于构造。 请参阅以下部分的 switch 语句。

基本 switch 语法

if 语句一样,switch 条件不需要括号。 最简单形式的 switch 语句如下所示:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    sec := time.Now().Unix()
    rand.Seed(sec)
    i := rand.Int31n(10)

    switch i {
    case 0:
        fmt.Print("zero...")
    case 1:
        fmt.Print("one...")
    case 2:
        fmt.Print("two...")
    }

    fmt.Println("ok")
}

如果多次运行前面的代码,则每次都会看到不同的输出。 (但是,如果在 Go Playground 中运行代码,则每次都会获得相同的结果。这是此服务的局限性之一。)

Go 会比较 switch 语句的每个用例,直到找到与条件匹配的项。 但请注意,前面的代码未涵盖 num 变量值的所有可能情况。 如果 num 最终为 5,则程序的输出为 ok

也可让默认用例更加具体,像下面这样包含它:

switch i {
case 0:
    fmt.Print("zero...")
case 1:
    fmt.Print("one...")
case 2:
    fmt.Print("two...")
default:
    fmt.Print("no match...")
}

请注意,对于 default 用例,不要编写验证表达式, i 变量的值是针对 case 语句进行验证的,default 情况会处理未经验证的值。

使用多个表达式

有时,多个表达式仅与一个 case 语句匹配。 在 Go 中,如果希望 case 语句包含多个表达式,请使用逗号 (,) 来分隔表达式。 此方法可避免代码重复。

以下代码示例演示了如何包含多个表达式。

package main

import "fmt"

func location(city string) (string, string) {
    var region string
    var continent string
    switch city {
    case "Delhi", "Hyderabad", "Mumbai", "Chennai", "Kochi":
        region, continent = "India", "Asia"
    case "Lafayette", "Louisville", "Boulder":
        region, continent = "Colorado", "USA"
    case "Irvine", "Los Angeles", "San Diego":
        region, continent = "California", "USA"
    default:
        region, continent = "Unknown", "Unknown"
    }
    return region, continent
}
func main() {
    region, continent := location("Irvine")
    fmt.Printf("John works in %s, %s\n", region, continent)
}

请注意,在 case 语句的表达式中包含的值对应于 switch 语句验证的变量的数据类型。 如果包含一个整数值作为新的 case 语句,程序将不会进行编译。

调用函数

switch 还可以调用函数。 在该函数中,可以针对可能的返回值编写 case 语句。 例如,以下代码调用 time.Now() 函数。 它提供的输出取决于当前工作日。

package main

import (
    "fmt"
    "time"
)

func main() {
    switch time.Now().Weekday().String() {
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
        fmt.Println("It's time to learn some Go.")
    default:
        fmt.Println("It's the weekend, time to rest!")
    }

    fmt.Println(time.Now().Weekday().String())
}

switch 语句调用函数时,无需更改表达式即可修改其逻辑,因为你始终会验证函数返回的内容。

此外,还可以从 case 语句调用函数。 例如,使用此方法可以通过正则表达式来匹配特定模式。 下面是一个示例:

package main

import "fmt"

import "regexp"

func main() {
    var email = regexp.MustCompile(`^[^@]+@[^@.]+\.[^@.]+`)
    var phone = regexp.MustCompile(`^[(]?[0-9][0-9][0-9][). \-]*[0-9][0-9][0-9][.\-]?[0-9][0-9][0-9][0-9]`)

    contact := "foo@bar.com"

    switch {
    case email.MatchString(contact):
        fmt.Println(contact, "is an email")
    case phone.MatchString(contact):
        fmt.Println(contact, "is a phone number")
    default:
        fmt.Println(contact, "is not recognized")
    }
}

请注意,switch 块没有任何验证表达式。 我们将在下一部分讨论该概念。

省略条件

在 Go 中,可以在 switch 语句中省略条件,就像在 if 语句中那样。 此模式类似于比较 true 值,就像强制 switch 语句一直运行一样。

下面是一个示例,说明了如何编写不带条件的 switch 语句:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())
    r := rand.Float64()
    switch {
    case r > 0.1:
        fmt.Println("Common case, 90% of the time")
    default:
        fmt.Println("10% of the time")
    }
}

该程序始终运行这种类型的 switch 语句,因为条件始终为 true。 一个条件 switch 块比一长串的 ifelse if 语句更易于维护。

使逻辑进入到下一个 case

在某些编程语言中,你会在每个 case 语句末尾写一个 break 关键字。 但在 Go 中,当逻辑进入某个 case 时,它会退出 switch 块,除非你显式停止它。 若要使逻辑进入到下一个紧邻的 case,请使用 fallthrough 关键字。

若要更好地了解此模式,请查看以下代码示例。

package main

import (
    "fmt"
)

func main() {
    switch num := 15; {
    case num < 50:
        fmt.Printf("%d is less than 50\n", num)
        fallthrough
    case num > 100:
        fmt.Printf("%d is greater than 100\n", num)
        fallthrough
    case num < 200:
        fmt.Printf("%d is less than 200", num)
    }
}

运行代码并分析输出:

15 is less than 50
15 is greater than 100
15 is less than 200

你是否看到错误?

请注意,由于 num 为 15(小于 50),因此它与第一个 case 匹配。 但是,num 不大于 100。 由于第一个 case 语句包含 fallthrough 关键字,因此逻辑会立即转到下一个 case 语句,而不会对该 case 进行验证。 因此,在使用 fallthrough 关键字时必须谨慎。 该代码产生的行为可能不是你想要的。