语法

1
2
3
4
5
6
7
8
9
10
switch initStmt; expr {
case expr1:
// 分支 1
case expr2_1, expr2_2:
// 分支 2
case exprN:
// 分支 N
default:
// 默认分支
}

顺序

按照定义顺序(从上到下,从左到右),先到先得,匹配后中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

func case1() int {
println("eval case1")
return 1
}

func case2_1() int {
println("eval case2_1")
return 0
}

func case2_2() int {
println("eval case2_2")
return 2
}

func case3() int {
println("eval case3")
return 3
}

func switchexpr() int {
println("eval switchexpr")
return 2
}

func main() {
switch switchexpr() {
case case1():
println("exec case1")
default: // 无论出现在什么位置,都只会在所有 case 都不匹配的时候执行
println("exec default")
case case2_2(), case2_1():
println("exec case2")
case case3():
println("exec case3")
}
}

// Output:
// eval switchexpr
// eval case1
// eval case2_2
// exec case2

匹配成功率高的 case 排在前面(上/左),有助于提升 switch 语句的执行效率

创新

C

  1. switch 语句对表达式类型有限制,只能是 int 或者枚举类型
  2. 每个 case 语句只可以有一个表达式
  3. 除非显式使用 break 跳出,程序默认总是执行下一个 case 语句

类型

只要类型支持比较操作,都可以作为 switch 语句中的表达式类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

type person struct {
name string
age int
}

func main() {
p := person{name: "John", age: 20}
switch p {
case person{name: "John", age: 20}:
println("John 20") // John 20
case person{name: "John", age: 30}:
println("John 30")
case person{name: "John", age: 40}:
println("John 40")
default:
println("No match")
}
}

当 switch 表达式的类型为布尔类型时,且求值结果始终true 时,可以省略 switch 后面的表达式

1
2
3
4
5
6
7
8
switch a, b, c := 1, 2, 3; true {
case true:
println("true", a) // true 1
case false:
println("false", b)
default:
println("default", c)
}
1
2
3
4
5
6
7
8
switch a, b, c := 1, 2, 3; { // 省略
case true:
println("true", a) // true 1
case false:
println("false", b)
default:
println("default", c)
}
1
2
3
4
5
6
7
8
switch { // 省略 initStmt
case true:
println("true") // true
case false:
println("false")
default:
println("default")
}

临时变量

与 if 和 for 一样,switch 支持 initStmt 来声明只在这个 switch 隐式代码块中使用的变量

1
2
3
4
5
6
switch a, b, c := 1, 2, 3; a + b + c {
case 6:
fmt.Printf("%d+%d+%d = %d\n", a, b, c, a+b+c) // 1+2+3 = 6
default:
println("default")
}

表达式列表

case 语句支持表达式列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void check_work_day(int a) {
switch (a) { // switch 支持 int 类型
case 1: // 没有显式 break,继续执行下一个 case
case 2:
case 3:
case 4:
case 5:
printf("Work day\n");
break;
case 6:
case 7:
printf("Weekend\n");
break;
default:
printf("Invalid day\n");
}
}
1
2
3
4
5
6
7
8
9
10
func check_work_day(a int) {
switch a {
case 1, 2, 3, 4, 5:
fmt.Println("work day")
case 6, 7:
fmt.Println("weekend")
default:
fmt.Println("invalid day")
}
}

fallthrough

取消默认执行下一个 case 的代码逻辑的语义,除非显式使用 fallthrough

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

func case1() int {
println("eval case1")
return 1
}

func case2() int {
println("eval case2")
return 2
}

func switchexpr() int {
println("eval switchexpr")
return 1
}

func main() {
switch switchexpr() {
case case1():
println("exec case1")
fallthrough
case case2(): // case2() is not evaluated
println("exec case2")
fallthrough
default:
println("exec default")
// fallthrough // cannot fallthrough final case in switch
}
}

// Output:
// eval switchexpr
// eval case1
// exec case1
// exec case2
// exec default

fallthrough 会跳过下一个 case 表达式的求值,而是直接进入对应分支

type switch

switch 语句支持求值结果为类型信息的表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var x interface{} = 13

switch x.(type) { // x 的静态类型为 interface{},动态类型为 int
case nil: // 具体的类型信息
println("nil")
case int:
println("int") // int
case float64:
println("float64")
case string:
println("string")
case bool:
println("bool")
default:
println("unknown")
}

x.(type) 为 switch 语句专有的,其中 x 必须为接口类型变量,求值结果为对应的动态类型

1
2
3
4
5
6
switch v := x.(type) { // v 为动态类型对应的值信息
case nil, int, float64, string, bool:
fmt.Printf("%T, %v\n", v, v) // int, 13
default:
fmt.Printf("%v\n", v)
}

Go 中所有类型都实现了 interface{} 类型

接口类型变量才能使用 type switch,并且所有 case 语句中的类型必须实现 switch 关键字后面变量的接口类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

type Human interface {
Run()
}

type Man struct {
}

func (m Man) Run() {
}

func main() {
var man Man
var human Human = man

switch human.(type) {
case Man: // ok
println("man")
// case int: // impossible type switch case: human (type Human) cannot have dynamic type int (missing Run method)
// println("int")
default:
println("default")
}
}

break

不带 label 的 break 中断执行并跳出的,是同一函数内 break 语句所在的最内层forswitchselect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

func main() {
sl := []int{5, 19, 6, 3, 8, 12}
firstEven := -1

for _, v := range sl {
switch v % 2 {
case 0:
firstEven = v
break // break out of the switch statement
case 1:
// do nothing
}
}

println(firstEven) // 12
}

label

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

func main() {
sl := []int{5, 19, 6, 3, 8, 12}
firstEven := -1

loop:
for _, v := range sl {
switch v % 2 {
case 0:
firstEven = v
break loop
case 1:
// do nothing
}
}

println(firstEven) // 6
}