Go switch 语句
在 Go 语言中,switch 语句为处理多个条件分支提供了一种干净且高效的方法。与一长串的 if-else if-else 语句相比,switch 语句通常能极大地提升代码的可读性和可维护性,尤其是在面对大量可能的条件判断时。
作为一种基础的控制流结构,它允许你根据变量或表达式的值来执行不同的代码块。
本章将深入探讨 Go 语言中 switch 语句的语法、功能特性以及各种实用的应用场景。
1. 基础 switch 语句
最基础的 switch 语句会将一个表达式的值与一系列可能的值进行对比。每一个可能的值都关联着一个 case 子句,当匹配成功时,就会执行该 case 下面的代码块。
1.1 基础语法
switch 语句的通用语法如下:
switch expression {
case value1:
// 如果 expression == value1,执行这里的代码
case value2:
// 如果 expression == value2,执行这里的代码
...
default:
// 如果以上所有 case 都不匹配,执行这里的代码
}expression(表达式): 需要被求值的表达式。它可以是一个变量、一个函数调用,或者任何合法的 Go 表达式。case value: 每个case子句指定一个值,用于和expression的结果进行比较。如果匹配,就执行该 case 后面的代码。default: default分支是可选的。如果存在,当没有任何case匹配时,程序就会执行这里的代码(类似于if-else中的else)。
1.2 代码示例
package main
import "fmt"
func main() {
grade := "B"
switch grade {
case "A":
fmt.Println("优秀!")
case "B":
fmt.Println("干得不错!")
case "C":
fmt.Println("及格。")
case "D":
fmt.Println("需要改进。")
case "F":
fmt.Println("不及格。")
default:
fmt.Println("无效的成绩。")
}
}在这个例子中,switch 语句对变量 grade 的值进行判断。因为 grade 是 "B",所以程序会执行 case "B": 下面的代码,在控制台打印出 "干得不错!"。如果 grade 匹配不到任何字母,就会执行 default 分支打印 "无效的成绩。"。
1.3 告别 break 语句
如果你学过 C、C++ 或 Java,你可能会习惯在每个 case 的末尾写上 break 来防止代码继续往下执行。在 Go 语言中,你不需要写 break! Go 的 switch 语句在执行完第一个匹配的 case 代码块后,会自动退出整个 switch 结构。如果你真的想让代码继续“掉进”下一个 case,你需要显式地使用 fallthrough 关键字(稍后会讲)。
2. switch 匹配多个值
Go 语言允许你在一个单独的 case 中包含多个匹配值,中间用逗号 , 隔开。这让你能轻松地把相似的情况归为一类。
2.1 语法与示例
switch expression {
case value1, value2, value3:
// 如果 expression 是 value1,或 value2,或 value3,都执行这里的代码
...
}来看一个判断工作日和周末的例子:
package main
import "fmt"
func main() {
day := "Wed" // 星期三
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
fmt.Println("今天是工作日。")
case "Sat", "Sun":
fmt.Println("今天是周末!")
default:
fmt.Println("无效的日期。")
}
}在这里,只要 day 的值是 "Mon" 到 "Fri" 中的任何一个,程序都会打印 "今天是工作日。"。
3. 无表达式的 switch
Go 的 switch 语句甚至可以不带任何表达式。在这种情况下,你可以把每个 case 子句写成一个返回布尔值 (true 或 false) 的条件判断。程序会从上往下计算,并执行第一个结果为 true 的 case。
这实际上就是一种书写起来极其优雅的 if-else if-else 链条!
3.1 语法与示例
switch {
case condition1:
// 如果 condition1 为 true,执行这里
case condition2:
// 如果 condition2 为 true,执行这里
...
default:
// 如果上面的条件都不为 true,执行这里
}来看一个根据年龄划分人群的例子:
package main
import "fmt"
func main() {
age := 25
// 注意:switch 后面什么都没有
switch {
case age < 13:
fmt.Println("儿童")
case age >= 13 && age < 20:
fmt.Println("青少年")
case age >= 20 && age < 65:
fmt.Println("成年人")
default:
fmt.Println("老年人")
}
}因为 age 是 25,第一个求值为 true 的条件是 age >= 20 && age < 65,所以程序会打印出 "成年人"。
4. fallthrough 穿透语句
fallthrough 关键字用于强制程序继续执行下一个 case 的代码块,即使下一个 case 的条件根本不匹配!这打破了 Go 默认的“匹配即退出”规则。
4.1 示例演示
package main
import "fmt"
func main() {
number := 2
switch number {
case 1:
fmt.Println("一")
case 2:
fmt.Println("二")
fallthrough // 触发穿透!
case 3:
fmt.Println("三")
default:
fmt.Println("其他")
}
}当 number 为 2 时,上述代码的输出结果将是:
二
三发生了什么? 程序匹配到了 case 2 并打印了 "二"。紧接着遇到了 fallthrough,程序被强行“踢”到了紧挨着的 case 3 的代码块中执行,打印了 "三"(完全无视了 number 其实不等于 3)。
注意:fallthrough 应该谨慎使用,因为如果滥用,它会让你的代码逻辑变得极其难以理解。
5. 类型开关 (Type switch)
类型开关 (Type switch) 是一种非常特殊的 switch 语句,它判断的不是变量的“值”,而是变量的“数据类型”。
这在处理接口 (Interface) 类型时极其有用,因为接口变量在运行期间可以装载各种不同底层类型的值。
5.1 语法与示例
switch v := interfaceValue.(type) {
case type1:
// 此时,v 的类型就是 type1
case type2:
// 此时,v 的类型就是 type2
...
default:
// 都不匹配的情况
}interfaceValue: 你想要探明真实类型的接口变量。v := interfaceValue.(type): 这是类型断言的特殊语法。它不仅判断类型,还会把底层真实的值赋给新变量v,并且v会自动变成那个匹配到的类型。
package main
import "fmt"
// 接收一个空接口,意味着可以传入任何类型的值
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("这是一个整数: %d\n", v)
case string:
fmt.Printf("这是一个字符串: %s\n", v)
case bool:
fmt.Printf("这是一个布尔值: %t\n", v)
default:
fmt.Printf("未知的类型\n")
}
}
func main() {
describe(10)
describe("Hello")
describe(true)
}在这个例子中,describe 函数里的类型开关准确地识别出了传入值的底层类型,并作出了对应的打印。