使用 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
块比一长串的 if
和 else 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
关键字时必须谨慎。 该代码产生的行为可能不是你想要的。