switch 是一个条件语句,它计算表达式并将其与可能匹配的列表进行比较,然后执行相应的代码块。它可以被认为是替换复杂if else
子句的惯用方式。
一个示例程序胜过一百个字。让我们从一个简单的示例开始,该示例将手指编号作为输入并输出该手指的名称:)。
例如,1 是拇指,2 是食指,依此类推。
package main
import (
"fmt"
)
func main() {
finger := 4
fmt.Printf("手指 %d 是 ", finger)
switch finger {
case 1:
fmt.Println("拇指")
case 2:
fmt.Println("食指")
case 3:
fmt.Println("中指")
case 4:
fmt.Println("无名指")
case 5:
fmt.Println("小指")
}
}
Run in Playground
在上面的程序中switch finger
,将 finger
与每个case
语句进行比较。从上到下计算案例,并执行第一个与表达式匹配的案例。在这种情况下,finger
有一个值4
,因此
手指 4 是 无名指
被打印。
不允许出现具有相同常量值的重复情况。如果你尝试运行下面的程序,编译器会报错
package main
import (
"fmt"
)
func main() {
finger := 4
fmt.Printf("手指 %d 是 ", finger)
switch finger {
case 1:
fmt.Println("拇指")
case 2:
fmt.Println("食指")
case 3:
fmt.Println("中指")
case 4:
fmt.Println("无名指")
case 4:
fmt.Println("无名指")
case 5:
fmt.Println("小指")
}
}
Run in Playground
在上面的程序中,输出:
./prog.go:19:7: duplicate case 4 (constant of type int) in expression switch
./prog.go:17:7: previous case
我们的手上只有5根手指。如果我们输入错误的手指号码会怎样?这就是默认情况出现的地方。当其他情况都不匹配时,将执行默认情况。
package main
import (
"fmt"
)
func main() {
finger := 11
fmt.Printf("手指 %d 是 ", finger)
switch finger {
case 1:
fmt.Println("拇指")
case 2:
fmt.Println("食指")
case 3:
fmt.Println("中指")
case 4:
fmt.Println("无名指")
case 5:
fmt.Println("小指")
default:
fmt.Println("无效数字")
}
}
Run in Playground
在上面的程序中finger
,它与任何情况都不匹配,因此在默认情况下会被打印。
手指 10 是 无效数字
这不一定default
是 switch 语句中的最后一个。它可以出现在任何位置。
您可能还注意到finger
的声明中的一个小变化。它是在开关本身中声明的。switch 可以包含在计算表达式之前执行的可选语句。finger
先声明,后在表达式中使用。本例中的范围finger
仅限于开关块。
可以在一个 case 中包含多个表达式,并用逗号分隔它们。
package main
import (
"fmt"
)
func main() {
letter := "i"
fmt.Printf("Letter %s is a ", letter)
switch letter {
case "a", "e", "i", "o", "u":
fmt.Println("vowel")
default:
fmt.Println("not a vowel")
}
}
Run in Playground
上面的程序判断是否letter
是元音。第 1 行中的代码case "a", "e", "i", "o", "u":
。11 匹配任何元音。由于i
是元音,因此该程序打印
Letter i is a vowel
switch 中的表达式是可选的,可以省略。如果省略表达式,则认为是 switch ,并且评估switch true
每个表达式的真值并执行相应的代码块。case
package main
import (
"fmt"
)
func main() {
num := 75
switch {
case num >= 0 && num <= 50:
fmt.Printf("%d 0-50之间", num)
case num >= 51 && num <= 100:
fmt.Printf("%d 51-100之间", num)
case num >= 101:
fmt.Printf("%d 100以上", num)
}
}
Run in Playground
在上面的程序中,switch 中不存在表达式,因此它被视为 true,并且对每种情况进行评估。case num >= 51 && num <= 100:
是true
并且程序打印
75 51-100之间
这种类型的开关可以被视为多个子句的替代if else
。
在 Go 中,执行 case 后立即从 switch 语句中产生控制。语句fallthrough
用于将控制转移到紧随已执行的情况之后出现的情况的第一条语句。
让我们编写一个程序来理解Fallthrough。我们的程序将检查输入的数字是否小于 50、100 或 200。例如,如果我们输入 75,程序将打印 75 小于 100 和 200。我们将使用 来实现此目的fallthrough
。
package main
import (
"fmt"
)
func number() int {
num := 15 * 5
return num
}
func main() {
switch num := number(); {
case num < 50:
fmt.Printf("%d 小于50 \n", num)
fallthrough
case num < 100:
fmt.Printf("%d 小于100 \n", num)
fallthrough
case num < 200:
fmt.Printf("%d 小于200 \n", num)
}
}
Run in Playground
Switch 和 case 表达式不必只是常量。它们也可以在运行时评估。在上面的程序中num
,初始化为number()
第 1 行函数的返回值。case num < 100:
为真,程序打印75 小于100
。当遇到fallthrough
时,控件移动到下一个情况的第一个语句并打印75 小于200
。程序的输出是
75 小于100
75 小于200
*fallthrough
应该是 *case
中的最后一个语句。如果它出现在中间的某个地方,编译器会报错fallthrough statement out of place
.
即使case评估结果为假,也会发生失败
使用时需要考虑一下fallthrough
的微妙之处。即使case评估结果为假,失败也会发生。
请考虑以下程序。
package main
import (
"fmt"
)
func main() {
switch num := 25; {
case num < 50:
fmt.Printf("%d 小于 50\n", num)
fallthrough
case num > 100:
fmt.Printf("%d 大于 100\n", num)
}
}
Run in Playground
在上面的程序中,num
是 25,小于 50,因此是第 1 行的情况。评估结果为 true。fallthrough
出现在第 1 行。
case num > 100,下一个case是false,因为 num < 100。但 Fallthrough 不考虑这一点。即使case评估结果为假,也会发生失败。
上面的程序将打印
25 is lesser than 50
25 is greater than 100
因此,请确保您了解使用 Fallthrough 时在做什么。
还有一件事是fallthrough
不能在switch的语句最后一种情况下使用,因为没有更多的情况可以失败。如果fallthrough
出现在最后一种情况下,将会导致以下编译错误。
cannot fallthrough final case in switch
该break
语句可用于在 switch 完成之前提前终止它。让我们将上面的示例修改为一个人为的示例,以了解break 是如何工作的。
让我们添加一个条件,如果num
小于 0,则开关应终止。
package main
import (
"fmt"
)
func main() {
switch num := -5; {
case num < 50:
if num < 0 {
break
}
fmt.Printf("%d 小于 50\n", num)
fallthrough
case num < 100:
fmt.Printf("%d 小于 100\n", num)
fallthrough
case num < 200:
fmt.Printf("%d 小于 200", num)
}
}
Run in Playground
上面的程序中num
是-5
.当程序到达if
语句时由于 num < 0,所以满足条件。break 语句在 switch 完成之前终止 switch,并且程序不会打印任何内容。
当 switch case 位于for循环内时,可能需要提前终止 for 循环。这可以通过标记 for 循环并在 switch 语句内使用该标签中断 for 循环来完成。
让我们看一个例子。我们编写一个程序来生成一个随机偶数。
我们将创建一个无限 for 循环,并使用 switch case 来确定生成的随机数是否为偶数。如果是偶数,则打印生成的数字并使用其标签终止 for 循环。
Intn
该rand
包的函数用于生成非负伪随机数。
package main
import (
"fmt"
"math/rand"
)
func main() {
randloop:
for {
switch i := rand.Intn(100); {
case i%2 == 0:
fmt.Printf("生成的偶数 %d", i)
break randloop
}
}
}
Run in Playground
在上面的程序中,for 循环被标记randloop
在第 1 行。 rand.Intn(100)
的函数生成 0 到 99 之间的随机数(不包括 100) 。如果生成的数字是偶数,则使用标签进行中断。
该程序打印,
生成的偶数 96
请注意,如果使用不带标签的break语句,则只会中断switch语句,而循环将继续运行。因此,标记循环并在 switch 内的 Break 语句中使用它,对于中断外部 for 循环是必要的。