4.4 switch语句

像许多C派生语言一样,Go也有switch语句。在一些语言中,开发者通常避免使用switch语句,但Go的switch语句不同,它没有对条件值的限制,并且不会连续执行case语句[1],这使得switch语句在Go语言中非常有用。

 本节介绍switch语句,如果你已经熟悉Go,可以在第7章学习接口时深入了解type-switch语句。

初看,Go中的switch语句与在C/C++、Java或JavaScript中的switch并没有什么不同,但Go语言的switch还是给我们带来了些许小惊喜。你可以在The Go Playground(https://oreil.ly/VKf4N)上运行示例4-19中的代码。

示例4-19:switch语句

输出如下所示:

让我们根据switch语句的特性来分析输出。与if语句一样,在switch中值比较语句周围不加括号。且与if语句一样,也可以声明一个作用域仅在switch语句所有分支内的变量。在上面的例子中,我们将变量word的作用域限定在switch语句的所有分支内。

所有case从句(包括可选的default从句)都包含在一组大括号中。但是需要注意,case从句的内容周围没有大括号。case从句(或default从句)中的代码可以有多行,它们都是分支逻辑的一部分。

case 5:分支中,我们声明了一个新的变量wordLen。这是一个新的代码块,可以在里面声明新的变量。就像任何其他代码块一样,在case从句块中声明的任何变量只在该代码块中可见。

值得高兴的是,在switch语句中不再需要将break语句放在每一个case从句的末尾。默认情况下,Go中的switch语句里的case不会连续执行。这比较符合Ruby或Pascal中的编程方式。

那么第一个问题是:如果case分支不会连续执行,那么如何处理多个分支具有相同逻辑的情况呢?在Go中,可以使用逗号将多个匹配的值分开,在以上代码示例中,我们希望匹配1,2,3,4或者6,7,8,9,所以当字面是acow时执行的case分支是一样的。

紧接着第二个问题:如果case分支不会连续执行,那么空case分支(例如上面代码示例中参数是6,7,8或9个字符的情况)会发生什么呢?在Go中,空case分支意味着什么也不做。这就是为什么我们看到octopusgopher作为参数的时候没有任何输出。

 为了完整起见,Go确实包含了一个fallthrough关键字,它会接着执行下一个case块。在使用它实现代码逻辑之前请三思,如果需要使用fallthrough,请尝试重新组织代码逻辑,以消除case分支彼此的依赖项。

我们在示例程序的switch语句中使用了一个整型的值,但并不是只能这样。任何可以使用==比较的类型均可以在switch语句中使用,包括所有内置类型,除了切片、映射、通道、函数以及包含以上这些类型字段的结构体。

尽管不需要在每个case从句的末尾使用break语句,但还是可以为了提前退出case分支而使用break语句[2]。不过break语句的使用可能表明代码逻辑太复杂了,需要考虑重构代码或者删除它。

switch语句的case中还有其他情况可能会用到break语句。如果for循环中有一个switch语句,而你想跳出for循环时,可以在for语句上加一个标签,并在break语句处使用标签。如果你不使用标签,Go会假定只是结束一个case分支。让我们看一个简单的例子,你可以在The Go Playground(https://oreil.ly/o2xg2)上运行示例4-20中的代码。

示例4-20:case分支缺少标签

运行这段代码会产生以下输出:

这明显不是我们的本意,我们的目的是当值为7的时候退出for循环。因此我们需要引入一个标签,就像在跳出嵌套的for循环时所做的那样。首先,对for语句进行标记:

break语句处使用标签:

你可以在The Go Playground(https://oreil.ly/gA0O3)上看到新的代码。当再次运行它时,得到了我们期望的输出:


[1]Go中的switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case语句,而是跳出整个switch,但是可以使用fallthrough强制执行后面的case语句中的代码。

[2]case分支的最后一行使用break与否效果是一样的。