Fork me on GitHub

Go语言开发-过程式编程-For循环语句

5.3. for循环语句

Go语言支持两种for循环语句,for和for…range语句。语法如下:

大括号是必需的,但是分号只有在可选的optionalPreStatement或optionalPostStatement语句存在时才需要;且这两个语句都必须是短声明语句。如果变量是在可选声明语句中创建的或需要获取range子句产生的值(如,使用:=运算符),则其作用域为整个for循环。

for循环中的布尔表达式的值必须是bool类型的,因为Go语言并不会将非bool类型的值自动转换成bool类型的。(参见表2.3)。

第二个for…range循环遍历了一个字符串并给出了字节偏移索引。对于一个7位ASCII字符串s,如果值为“XabYcZ”,产生的索引为0,1,2,3,4,5,但是对于一个UTF-8字符串s,如果值为“XαβYγZ”,则产生的索引为0,1,3,5,6,8。在大多数情况下,第一个遍历字符串的for…range循环语法比第二个更便捷。

对于非空的切片或数组,第三个for…range循环通过遍历该数组或切片并给出了索引位置从0到len(slice)-1的元素。该语法和第一个遍历数组或切片的for…range语法都是非常常用的。这两种语法也特别解释了为何在Go语言中很少使用for循环语句。

for…range循环可以以键值对的形式遍历映射中的元素,但是这种遍历是无序的。如果需要排序,其中一种解决方法是使用第二种语法,将键填充到一个切片中,并对该切片排序。在之前的章节中我们已经讲解过这种用法。另一种解决方法是使用一个有序数据结构,例如,一个有序的映射。

如果将上面的语法应用于一个空的字符串、数组、切片或映射,for循环将会安全的不执行任何操作,控制流会从后面的语句继续。

for循环可以使用break语句来终止,并继续执行for循环之后的语句,或者,如果break语句指定了一个label,则程序会继续执行拥有该label的最内层的for、switch或select语句。也可以通过使用一个continue语句来让程序继续从for循环的条件开始处或range子句处开始下一次遍历(或结束循环)。

我们已经讲解了多个使用for语句的例子,包括for…range循环、无限循环和普通的for循环,但是在Go程序中普通的for循环使用频率并不高,这是因为其他的循环往往更便捷。当然,在本书的后续章节包括本章后面的小节,我们将会介绍更多的关于for循环的例子。下面是一个小例子。

假设我们有一个二维切片(如,[][]int),并且想要查找一下该切片是否含有一个特定的值。这里我们有两种查找方法,他们都使用了第二中for…range循环来遍历一个数组或切片。

label是后面跟一个冒号的标识符。上面的两段代码功能一样,但是右侧的代码段是更加简短清晰,因为一旦找到要搜索的值(x),就会通过指定了label的break语句跳转到外层循环。如果我们嵌套了多重循环(例如,遍历三维的数据),则使用带有label的break语句可以具有更加明显的优势。

label可以用于for循环、switch语句和select语句。break和continue语句都可以带有label且都可以用于for循环内部。其中break语句也可以用于switch和select语句内部,且break也可以带有label标签。

label语句也可以单独出现,这样它们就可以是goto语句要跳转的(使用goto label语法) 的对象。如果goto语句跳过了任何创建变量的语句,则Go程序的执行结果是未知的,如果幸运的话,程序崩溃,但是也可能会继续运行并产生错误的结果。一种使用goto语句的场景是在自动生成代码时,因为在这种情况下goto语句是非常便捷的且无需关心意大利面式的代码。虽然在编撰本书时,Go语言中有超过30个源代码文件使用了goto语句,但是本书中完全没有使用goto语句的例子,我们提倡尽量避免使用它。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注