switch
语句对 switch
表达式的结果类型,以及各个 case
表达式中子表达式的结果类型都是有要求的。
毕竟,在 Go
语言中,只有类型相同的值之间才有可能被允许进行判等操作。
1. switch 类型和 case 类型不匹配
1.1 switch 类型和 case 类型不能转换场景
package main
import "fmt"
func main() {
value1 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch 1 + 3 { // 这条语句无法编译通过。
case value1[0], value1[1]:
fmt.Println("0 or 1")
case value1[2], value1[3]:
fmt.Println("2 or 3")
case value1[4], value1[5], value1[6]:
fmt.Println("4 or 5 or 6")
}
}
输出结果:
invalid case value1[0] in switch on 1 + 3 (mismatched types int8 and int)
invalid case value1[1] in switch on 1 + 3 (mismatched types int8 and int)
原因是:
switch
表达式的结果值是无类型的常量,比如 1 + 3
的求值结果就是无类型的常量 4
,那么这个常量会被自动地转换为此种常量的默认类型的值,比如整数 4
的默认类型是 int
,又比如浮点数 3.14
的默认类型是 float64
。
因此,由于上述代码中的 switch
表达式的结果类型是 int
,而那些 case
表达式中子表达式的结果类型却是 int8
,它们的类型并不相同,所以这条 switch
语句是无法通过编译的。
1.2 switch 类型和 case 类型可以转换场景
package main
import "fmt"
func main() {
value2 := [...]int8{0, 1, 2, 3, 4, 5, 6}
fmt.Printf("value2[4] type is %T\n ", value2[4])
switch value2[4] {
case 0, 1:
fmt.Println("0 or 1")
case 2, 3:
fmt.Println("2 or 3")
case 4, 5, 6:
fmt.Println("4 or 5 or 6")
}
}
输出结果:
value2[4] type is int8
4 or 5 or 6
switch
表达式的结果值是 int8
类型的,而那些 case
表达式中子表达式的结果值却是无类型的常量了。这与之前的情况恰恰相反。
能够编译成功的原因是,如果 case
表达式中子表达式的结果值是无类型的常量,那么它的类型会被自动地转换为 switch
表达式的结果类型,又由于上述那几个整数都可以被转换为 int8
类型的值,所以对这些表达式的结果值进行判等操作是没有问题的。
总结:
类型自动转换
- 如果
switch
表达式后面的是无类型的值,它不会发生自动转换类型。 - 但是如果
case
后面的是无类型的值的话会被自动转换成switch
后面的类型。
2. case 表达式中的子表达式不能重复(只针对结果值为常量的子表达式)
switch
语句不允许 case
表达式中的子表达式结果值存在相等的情况,不论这些结果值相等的子表达式,是否存在于不同的 case
表达式中,都会是这样的结果。
package main
import "fmt"
func main() {
value3 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value3[4] { // 这条语句无法编译通过。
case 0, 1, 2:
fmt.Println("0 or 1 or 2")
case 2, 3, 4:
fmt.Println("2 or 3 or 4")
case 4, 5, 6:
fmt.Println("4 or 5 or 6")
}
}
编译错误:
duplicate case 2 in switch
duplicate case 4 in switch
3. case 表达式中的子表达式不是常量时则可以重复
package main
import "fmt"
func main() {
value5 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value5[4] {
case value5[0], value5[1], value5[2]:
fmt.Println("0 or 1 or 2")
case value5[2], value5[3], value5[4]:
fmt.Println("2 or 3 or 4")
case value5[4], value5[5], value5[6]:
fmt.Println("4 or 5 or26")
}
}
输出结果:
2 or 3 or 4
只要 switch
表达式的结果值与某个 case
表达式中的任意一个子表达式的结果值相等,该 case
表达式所属的 case
子句就会被选中。并且,一旦某个 case
子句被选中,其中的附带在 case
表达式后边的那些语句就会被执行。与此同时,其他的所有case子句都会被忽略。
不过,这种绕过方式对用于类型判断的 switch
语句(以下简称为类型switch语句)就无效了。因为类型 switch
语句中的 case
表达式的子表达式,都必须直接由类型字面量表示,而无法通过间接的方式表示。代码如下:
package main
import "fmt"
func main() {
value6 := interface{}(byte(127))
switch t := value6.(type) { // 这条语句无法编译通过。
case uint8, uint16:
fmt.Println("uint8 or uint16")
case byte: // duplicate case byte in type switch
fmt.Printf("byte")
default:
fmt.Printf("unsupported type: %T", t)
}
}
原因是:
byte
类型是 uint8
类型的别名类型。因此,它们两个本质上是同一个类型,只是类型名称不同罢了。
在这种情况下,这个类型 switch
语句是无法通过编译的,因为子表达式 byte
和 uint8
重复了。