• 表达式型switch:包含与switch表达式的值进行比较的表达式。
  • 类型型switch:包含与switch表达式的类型进行比较的类型。

switch 使用方式

switch var{}

  1. switch 表达式可以执行一个简单语句完成运算从而得到表达式的值。
1
2
3
4
5
6
7
8
switch var {    // switch 会判断var的类型
    case val1:  // case 会判断val1的类型以便和var能比较
        // ...
    case val2:
        // ...
    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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main

import (
    "fmt"
)

const B1 = false

func main()  {
    switch B1 {
    case false:
        fmt.Println("fallthrough 语句 接到执行下一个语句")
        fallthrough
    case true:
        fmt.Println("true")
        fallthrough
    case false:
        fmt.Println(123)
        fallthrough
    case true:
        fmt.Println(456789)
    default:
        fmt.Println("default")
    }

    fmt.Println("default 1234")

    // > ----------------------------------------------------

    var i1 = 2
    switch i1 {
    default:
        fmt.Println("default")
    case 0,1,2,3:
        fmt.Println("123456789")
    case 4,5,6,7:
        fmt.Println("987654321")
    }
    
    // > ----------------------------------------------------

    switch i1 {
    default:
        fmt.Println("default")
    case 0:
    case 1:
    case 2:
    case 3:
        fmt.Println("123456789")
    case 4,5,6,7:
        fmt.Println("987654321")
    }
    
    // 注意 case 0,1,2,3: 形式和 case 0: case 1: case 2: 这种形式的区别
    
    // Output:
    // fallthrough 语句 接到执行下一个语句
    // true
    // 123
    // 456789
    // default 1234
    // 123456789
}

switch{}

  1. 不提供任何被判断的值(实际上默认为判断是否为true)然后在每个case分支中检测不同的条件,当任一分支的测试结果为true时,该分支的代码会被执行,此时语句相当于switch true
1
2
3
4
5
6
7
8
switch { // 默认推导为布尔类型 true
    case condition1: // condition1比较条件
        // ...
    case condition2:
        // ...
    default:
        // ...
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
)

func main()  {
    var x, y, z = 2, 1, 3

    // switch {} 等价于 switch true {}
    switch {
    case x < y:
        fmt.Printf("x:%d,y:%d\n", x, y)
    case x < z:
        fmt.Printf("x:%d,z:%d\n", x, z)
    case z == 3:
        fmt.Println("z==4\n")
    }
    
    // Output:
    // x:2,z:3
}

switch Init; var{}

  1. switch语句第三种形式,包含一个初始化语句。
1
2
3
4
5
6
7
8
switch Init; var {
    case val1:
        // ...
    case val2:
        // ...
    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
package main

import (
    "fmt"
)

func main()  {
    // switch x, y, z := 2, 1, 3; {} 等价于 switch x, y, z := 2, 1, 3; true {}
    // 等价于
    // {
    //     x, y, z := 2, 1, 3;
    //     switch true {
    //     // ... ...
    //     }
    // }
    switch x, y, z := 2, 1, 3; {
    case x < y:
        fmt.Printf("x:%d,y:%d\n", x, y)
    case x < z:
        fmt.Printf("x:%d,z:%d\n", x, z)
    case z == 3:
        fmt.Println("z==4\n")
    }

    switch x, y, z := 2, 1, 3; false {
    case x < y:
        fmt.Printf("x:%d,y:%d\n", x, y)
    case x < z:
        fmt.Printf("x:%d,z:%d\n", x, z)
    case z == 3:
        fmt.Println("z==4\n")
    }
    
    // Output:
    // x:2,z:3
    // x:2,y:1
}
 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
46
47
48
49
50
51
52
53
54
55
package main

import "fmt"

func main() {
    var j = 0
    switch j {
    case 0: // 注意这种和case 0, 1:形式的区别
    case 1:
        fmt.Println("11")
    case 2:
        fmt.Println("22")
    default:
        fmt.Println("def def")
    }

    var k = 0
    switch k {
    case 0:
        fmt.Println("fallthrough")
        fallthrough
    case 1:
        fmt.Println("111")
    case 2:
        fmt.Println("211")
    default:
        fmt.Println("def def def")
    }

    var m = 0
    switch m {
    case 0, 1:
        fmt.Println("1111")
    case 2:
        fmt.Println("2111")
    default:
        fmt.Println("def def def def")
    }

    var n = 0
    switch {
    case n > 0 && n < 10:
        fmt.Println("i > 0 and i < 10")
    case n > 10 && n < 20:
        fmt.Println("i > 10 and i < 20")
    default:
        fmt.Println("def def def def def")
    }
    
    // Output:
    // fallthrough
    // 111
    // 1111
    // def def def def def
}

表达式型switch

  1. 如果switch表达式求值为无类型常量,则首先将其转换为默认类型(整型默认int,浮点数默认float64,字符串默认string,复数默认complex128)。
    • 如果是无类型的布尔值,则首先将其转换为bool类型。
    • 预先声明的无类型值nil不能用作开关表达式(由于switch转换nil为默认类型报错)。
  2. 如果switch表达式是无类型的,则首先将其转换为switch表达式的类型。
    • 对于每个(可能已转换的)switch表达式xswitch表达式的值txt必须可以进行有效的比较。
  3. switchdefault字句中,最后一个非空语句可以是fallthrough语句。
    • 以指示应该从该字句的末尾流向下一个字句的第一个语句,无论下一个字句的条件是否满足。
    • 出现fallthrough语句后,它后面只能接下一个字句。
1
2
3
4
5
6
7
8
switch expr {
    case v1:
        // pass
    case v2:
        // pass
    default:
        // pass
}

nil不能作为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
26
27
28
29
package main

import "fmt"

func main()  {
    // 这里switch将nil转换成默认类型进行以下比较时报错
    // 和之前的 a := nil 或 var a = nil 一样报错不能判断出a的具体类型
    // 由此可见swicth需要确定变量的唯一类型
    switch nil { // 报错
    case nil:
        fmt.Println("nil")
    default:
        fmt.Println("default")
    }

    // .\os.go:8:2: use of untyped nil

    // 下面这种却是可以
    var m map[string]string
    switch m { // 这里能确认m是map类型
    case nil:
        fmt.Println("nil")
    default:
        fmt.Println("default")
    }

    // Output:
    // nil
}

无类型常量用作switch

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

import "fmt"

const Sw = 12

func main() {
    switch Sw { // Sw被默认推导为int类型
    // (untyped float constant) truncated to int
    // 报错,1.1被默认推导为float64类型无法与int类型比较
    case 1.1:			
        fmt.Println()
    }
}

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import "fmt"

func main() {
    // 定义局部变量
    var grade string = "B"
    var marks int = 90

    switch marks {
    case 90:
        grade = "A"
    case 80:
        grade = "B"
        // 这里与其他语言写法的根本原因是go默认会添加break语句,而其他语言没有这一特性的原因
    case 50, 60, 70: // 这里区分其他语言 case 50: case 60: case 70:
        grade = "C"
    default:
        grade = "D"
    }

    // switch 省略条件 默认为 switch true {} 
    // 和for {} 一样省略条件默认为 for true {}
    switch {
    case grade == "A":
         fmt.Printf("优秀\n")
    case grade == "B", grade == "C":
        fmt.Printf("良好\n")
    case grade == "D":
        fmt.Printf("及格\n")
    case grade == "F":
        fmt.Printf("不及格\n")
    default:
        fmt.Printf("差\n")
    }

    fmt.Printf("你的等级是 %s\n", grade)
    
    // Output:
    // 优秀
    // 你的等级是 A
}

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
package main

import (
    "fmt"
)

func main()  {
    // fallthrough 关键字 继续执行下一个case不判断case值
    switch {
    case false:
        fmt.Println("fallthrough 语句 接到执行下一个语句")
        fallthrough
    case true:
        fmt.Println("true")
        fallthrough
    case false:
        fmt.Println(123)
        fallthrough
    case true:
        fmt.Println(456789)
        // fallthrough强制执行【紧挨着相邻】的case或default块,
        // 如果后面没有紧挨着的则报错
        fallthrough
    default:
       fmt.Println("default")
    }
    
    // Output:
    // true
    // 123
    // 456789
    // default
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func main() {
    var k = 2
    switch k {
    case 0:
        fmt.Println("fallthrough")
    case 2:
        fmt.Println("211")
        fallthrough
        // 可见,fallthrough 后紧挨着 default 也会执行它。
    default:
        fmt.Println("def def def")
    case 1:
        fmt.Println("111")
    }

    // Output:
    // 211
    // def def def
}
  • fallthroughdefault一起使用。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
switch {
default:    // 比如这里当匹配条件都不通过,则到default这里
    fmt.Println("1")
    fallthrough // fallthrough后继续执行后面的case
case true:
    fmt.Println("2")
}
// Output:
// 2

switch {
default: // 比如这里当匹配条件都不通过,则到default这里
    fmt.Println("1")
    fallthrough // fallthrough后继续执行后面的case
case false:
    fmt.Println("2")
}
// Output:
// 1
// 2

类型型switch

  1. 比较的类型而不是值,它在其他方面类似表达式型switch,只不过分支选择的是类型而不是值。
  2. 它由一个特殊的switch表达式标记,该表达式使用类型断言的形式来进行动态类型判断。

x.(type)

  1. switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。
  2. type switch 语句格式如下:
1
2
3
4
5
6
7
8
switch x.(type) {
    case type:
        statement(s)
    case type:
        statement(s)
    default:
        statement(s)
}
 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
46
47
48
49
50
51
52
package main

import (
    "fmt"
)

func main()  {
    // 定义变量t 接口类型 interface{} 可以是任何其他类型
    var t interface{}
    t = functionOfSomeType()
    // switch t.(type) { ... }
    // t.(type) 断言t的类型 .(type)形式必须配合switch使用
    switch t1 := t.(type) {
        default:
            fmt.Printf("default Type %T\n", t1)
        case bool:
            fmt.Printf("bool %t\n", t1)
        case int:
            fmt.Printf("integer %d\n", t1)
        case *bool:
            fmt.Printf("pointer bool %t\n", *t1)
        case *int:
            fmt.Printf("pointer integer %d\n", *t1)
    }
}

//func functionOfSomeType () bool {
//  return false
//}
// bool false

//func functionOfSomeType () uint {
//  return 123
//}
// default Type uint

//func functionOfSomeType () int {
//  return 123
//}
// integer 123

//func functionOfSomeType () *int {
//  a := 123
//  return &a
//}
// pointer integer 123

func functionOfSomeType () *bool {
    a := true
    return &a
}
// pointer bool true

注意

  1. val1val2可以是同类型的任意值,类型不局限于常数或整数,但必须是相同的类型,或最终结果为相同类型的表达式。
  2. 前花括号{必须和switch关键字在同一行。
  3. 可以同时测试多个可能符合条件的值,使用逗号分割它们。
    • case val1, val2, val3而在其他语言中则是case val1: case val2: case val3:这种形式。
    • 一旦成功地匹配到某个分支,在执行完相应代码后就会退出整个switch代码块。
    • 也就是说,不需要特别使用break语句来表示结束,如果使用了仍然是在switch块中。
  4. 如果在执行完每个分支的代码后,还是希望继续执行后续分支的代码。
    • 可以使用fallthrough关键字来达到目的,fallthrough强制执行后面的(紧挨着的)下一条分支代码,不管是case或default分支都会执行。
    • 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
package main

import (
    "fmt"
)

func main()  {
    switch a := 1; {
    case a == 1:
        fmt.Printf("a == %d\n", a)
        fallthrough
    case a == 2:
        fmt.Println("a == 2")
    case a == 3:
        fmt.Println("a == 3")
        fallthrough
    case a == 5:
        fmt.Println("a == 5")
        fallthrough
    default:
        fmt.Println("default")
    case a == 4:
        fmt.Println("a == 4")
    }
    
    // Output:
    // a == 1
    // a == 2
}