switch 是多分支选择的利器。Go语言的 switch 相比C语言做了重要改进:每个case默认带有break(不会自动穿透),case表达式支持多种类型(不限于整数),且可以没有表达式而充当“级联if-else”。另外,fallthrough 关键字可以强制穿透到下一个case。
switch无需在每个case后写break,同时支持逗号分隔的多条件匹配,极大地简化了逻辑。
最简单的形式:比较表达式与各个case的值,执行匹配到的分支,没有匹配则执行default(可选)。
package main
import "fmt"
func main() {
day := "Saturday"
switch day {
case "Monday":
fmt.Println("周一,努力工作")
case "Tuesday", "Wednesday", "Thursday":
fmt.Println("周中,持续前进")
case "Friday":
fmt.Println("周五,即将周末")
case "Saturday", "Sunday":
fmt.Println("周末,放松一下")
default:
fmt.Println("无效的日期")
}
}
要点:多个条件可以用逗号分隔(逻辑或),不需要写break,Go会自动在匹配的case末尾添加隐含的break。
类似于if,可以在switch关键字后添加一个简短语句(通常是变量声明),该变量作用域仅限于整个switch块。
switch score := 85; {
case score >= 90:
fmt.Println("优秀")
case score >= 80:
fmt.Println("良好")
default:
fmt.Println("合格")
}
// score 在此处不可见
当switch后面不跟表达式时,每个case被当作布尔值处理,相当于编写多分支的if-else语句,但更加清晰。
score := 88
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
case score >= 60:
fmt.Println("D")
default:
fmt.Println("F")
}
这种形式非常适合区间判断,比多层if-else更扁平易读。
Go默认不会穿透到下一个case,但使用fallthrough可以强制执行下一个case的代码块(不会重新判断该case的条件)。
n := 2
switch n {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
fallthrough
case 3:
fmt.Println("3")
case 4:
fmt.Println("4")
}
// 输出: 2 3
fallthrough可能会使逻辑混乱,多数场景下不需要。仅少数情况(如模拟C语言穿透)才有必要。
类型开关用于判断接口变量的具体类型。语法:switch x.(type) { ... },每个case后面跟一个类型。
func checkType(v interface{}) {
switch t := v.(type) {
case int:
fmt.Printf("整型: %d\n", t)
case string:
fmt.Printf("字符串: %s\n", t)
case bool:
fmt.Printf("布尔: %t\n", t)
case []int:
fmt.Printf("整数切片,长度: %d\n", len(t))
default:
fmt.Printf("未知类型: %T\n", t)
}
}
func main() {
checkType(42) // 整型: 42
checkType("hello") // 字符串: hello
checkType(true) // 布尔: true
checkType([]int{1,2}) // 整数切片,长度: 2
}
.(type) 只能在 switch 语句中使用,且接口变量必须是空接口 interface{} 或定义过的方法集接口。
由于 Go 的 case 自带 break,通常不需要显式写 break。但如果 case 内包含一个循环,想提前终止整个 switch 块,可以使用带标签的 break。
outerSwitch:
switch x := 2; x {
case 1:
fmt.Println(1)
case 2:
for i := 0; i < 5; i++ {
if i == 2 {
break outerSwitch // 跳出 switch,而不是仅跳出 for
}
fmt.Println("i=", i)
}
fmt.Println("这行不会执行")
}
// 输出: i=0 i=1
无表达式 switch 可以视为空 switch,每个 case 是一个布尔表达式。有时候可以使用空白标识符 _ 忽略不需要的值。
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
if len(os.Args) != 4 {
fmt.Println("用法: calc <num1> <op> <num2>")
return
}
a, err1 := strconv.ParseFloat(os.Args[1], 64)
b, err2 := strconv.ParseFloat(os.Args[3], 64)
if err1 != nil || err2 != nil {
fmt.Println("数字格式错误")
return
}
op := os.Args[2]
var result float64
switch op {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
if b == 0 {
fmt.Println("除数不能为零")
return
}
result = a / b
default:
fmt.Println("不支持的操作符,仅支持 + - * /")
return
}
fmt.Printf("%g %s %g = %g\n", a, op, b, result)
}
运行示例:go run calc.go 10 + 20 → 10 + 20 = 30
switch 清晰表达的多路分支,优先选用 switch 而非多级 if-else。fallthrough,请添加注释说明意图,避免造成“逻辑陷阱”。interface{} 使用类型开关时,注意 case nil 可以捕获未赋值的接口。switch 简洁而强大,极大地提升了多分支判断的可读性。掌握后能够写出更优雅的代码。下一章我们将详细学习 Go 语言的函数,包括多返回值、可变参数、匿名函数和闭包等。