在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。以下为大多编程语言循环程序的流程图:

Go 语言提供了以下几种类型循环处理语句:
| 循环类型 | 描述 |
|---|---|
| for 循环 | 重复执行语句块 |
| 循环嵌套 | 在 for 循环中嵌套一个或多个 for 循环 |
循环控制语句可以控制循环体内语句的执行过程。GO 语言支持以下几种循环控制语句:
| 控制语句 | 描述 |
|---|---|
| break 语句 | 经常用于中断当前 for 循环或跳出 switch 语句 |
| continue 语句 | 跳过当前循环的剩余语句,然后继续进行下一轮循环 |
| goto 语句 | 将控制转移到被标记的语句 |
for 循环
for 循环是一个循环控制结构,可以执行指定次数的循环 Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号
for 循环的几种形式
和 C 语言、Java、JavaScript的 for 一样
for init; condition; post { }
先对表达式 1 赋初值,判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句
- init 一般为赋值表达式,给控制变量赋初值
- condition 关系表达式或逻辑表达式,循环控制条件
- post 一般为赋值表达式,给控制变量增量(increment)或减量(decrement)

和 C 的 while 一样:
for condition { }
和 C 的 for(;;) 一样:
for { }
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环
for key, value := range oldMap {newMap[key] = value}//和JavaScript中for中操作对象,数组的对比var obj = { a: 1, b: 2, c:3 }for (const [k,v] of Object.entries(obj)) {console.log(k,v)}var obj = { a: 1, b: 2, c:3 }for (const k in obj) {console.log(k, obj[k])}var obj = [1,2,3]for (const k in obj) {console.log(k, obj[k])}
计算 1 到 10 的数字之和
package mainimport "fmt"func main() {sum := 0for i := 0; i <= 10; i++ {sum += i}fmt.Println(sum)}// 输出结果:55
sum 小于 10 的时候计算 sum 自相加后的值
package mainimport "fmt"func main() {sum := 1for ;sum <= 10; {sum += sum}fmt.Println(sum)// 这样写也可以,更像 While 语句形式for sum <= 10{sum += sum}fmt.Println(sum)}
无限循环
如果循环中条件语句永远不为 false 则会进行无限循环,我们可以通过 for 循环语句中只设置一个条件表达式来执行无限循环:
package mainimport "fmt"func main() {sum := 0for;;{ fmt.Printf(";;\n"); }for true { fmt.Printf("这是条件为true的无限循环\n"); }for {sum++ // 无限循环下去fmt.Printf("无参数的无限循环。\n");}fmt.Println(sum) // 无法输出}
⚠️ 要停止无限循环,可以在命令窗口按下ctrl+c
循环嵌套
Go 语言允许用户在循环内使用循环, 以下为 Go 语言嵌套循环的格式:
for [(init; condition; increment) | condition | Range] {for [(init; condition; increment) | condition | Range]{statement(s);}statement(s);}
使用循环嵌套来输出 2 到 100 间的素数
package mainimport "fmt"func main() {// 定义局部变量var i, j intfor i=2; i < 100; i++ {for j=2; j*j <= i; j++ {if(i%j==0) {break; // 如果发现因子,则不是素数}}if(j*j > i) {fmt.Printf("%d 是素数\n", i);}}}/*2 是素数3 是素数5 是素数7 是素数11 是素数13 是素数17 是素数19 是素数23 是素数29 是素数31 是素数*/
for-range 范围(Range)
Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、集合(map)、通道(channel)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 键值对
这种格式的循环可以对字符串、数组、切片等进行迭代输出元素
package mainimport "fmt"func main() {strings := []string{"google", "runoob"}for i, s := range strings {fmt.Println(i, s)}numbers := [6]int{1, 2, 3, 5}for i,x:= range numbers {fmt.Printf("第%d位 x 的值 = %d\n", i,x)}}/*0 google1 runoob第0位 x 的值 = 1第1位 x 的值 = 2第2位 x 的值 = 3第3位 x 的值 = 5第4位 x 的值 = 0第5位 x 的值 = 0*/
package mainimport "fmt"func main() {//这是我们使用range去求一个slice的和。使用数组跟这个很类似nums := []int{2, 3, 4}sum := 0for _, num := range nums[1:] {sum += num}fmt.Println("sum:", sum)//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。for i, num := range nums {if num == 3 {fmt.Println("index:", i)}}//range也可以用在map的键值对上kvs := map[string]string{"a": "apple", "b": "banana"}for k, v := range kvs {fmt.Printf("%s -> %s\n", k, v)}//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。for i, c := range "go" {fmt.Println(i, c)}c := make(chan int, 12)go fibonacci(cap(c), c)for i := range c { fmt.Println(i) }}func fibonacci(n int, c chan int) {x, y := 0, 1for i := 0; i <= n; i++ {c <- xx, y = y, x+y}close(c)}/* 以上实例运行输出结果为:sum: 7index: 1a -> appleb -> banana0 1031 11101123581321345589144*/
break 语句
Go 语言中 break 语句用于以下两方面:
- 用于循环语句中跳出循环,并开始执行循环之后的语句。
- break 在 switch(开关语句)中在执行一条 case 后跳出语句的作用。
- 在多重循环中,可以用标号 label 标出想 break 的循环
break 语法格式与语句流程图
break;
在变量 a 大于 15 的时候跳出循环
package mainimport "fmt"func main() {// 定义局部变量var a int = 10// for 循环for a < 20 {fmt.Printf("a的值为 : %d\n", a);a++;if a > 15 {break; //使用 break 语句跳出循环}}}/*a的值为 : 10a的值为 : 11a的值为 : 12a的值为 : 13a的值为 : 14a的值为 : 15*/
有多重循环,使用标记和不使用标记的区别
package mainimport "fmt"func main() {// 不使用标记fmt.Println("---- break ----")for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)break}}// 使用标记fmt.Println("---- break label ----")re:for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)break re}}}/*---- break ----i: 1i2: 11i: 2i2: 11i: 3i2: 11---- break label ----i: 1i2: 11*/
continue 语句
Go 语言的 continue 语句 有点像 break 语句。但是 continue 不是跳出循环,而是跳过当前循环执行下一次循环语句 for 循环中,执行 continue 语句会触发 for 增量语句的执行 在多重循环中,可以用标号 label 标出想 continue 的循环
continue 语法格式与语句流程图
continue;
在a=15 的时候跳过本次循环执行下一次循环
package mainimport "fmt"// func main() {// var a int = 10 // 定义局部变量// for a < 20 {// if a == 15 {// a = a + 1;// continue; // 跳过此次循环,即使跳过一次下面的打印// }// fmt.Printf("a 的值为 : %d\n", a);// a++;// }// }func main() {for a :=10 ;a < 20;a++ {if a == 15 {continue; // 跳过此次循环,即使跳过一次下面的打印}fmt.Printf("a 的值为 : %d\n", a);}}/*a 的值为 : 10a 的值为 : 11a 的值为 : 12a 的值为 : 13a 的值为 : 14a 的值为 : 16a 的值为 : 17a 的值为 : 18a 的值为 : 19*/
多重循环,使用标记和不使用标记的区别
package mainimport "fmt"func main() {// 不使用标记fmt.Println("---- continue ---- ")for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)continue}}// 使用标记fmt.Println("---- continue label ----")re:for i := 1; i <= 3; i++ {fmt.Printf("i: %d\n", i)for i2 := 11; i2 <= 13; i2++ {fmt.Printf("i2: %d\n", i2)continue re}}}/* ---- continue ----i: 1i2: 11i2: 12i2: 13i: 2i2: 11i2: 12i2: 13i: 3i2: 11i2: 12i2: 13---- continue label ----i: 1i2: 11i: 2i2: 11i: 3i2: 11*/
goto 语句
Go 语言的 goto 语句可以无条件地转移到过程中指定的行 goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能 但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难
goto 语法格式与语句流程图
goto label;...label: statement;

在a=15的时候跳过本次循环并回到循环的开始语句LOOP处
package mainimport "fmt"func main() {// 定义局部变量var a int = 10// 循环LOOP: for a < 20 {if a == 15 {// 跳过迭代a = a + 1goto LOOP}fmt.Printf("a的值为 : %d\n", a)a++}}/*a的值为 : 10a的值为 : 11a的值为 : 12a的值为 : 13a的值为 : 14a的值为 : 16a的值为 : 17a的值为 : 18a的值为 : 19*/
打印九九乘法表
package mainimport "fmt"func main() {//print9x()gotoTag()}//嵌套for循环打印九九乘法表func print9x() {for m := 1; m < 10; m++ {for n := 1; n <= m; n++ {fmt.Printf("%dx%d=%d ",n,m,m*n)}fmt.Println("")}}//for循环配合goto打印九九乘法表func gotoTag() {for m := 1; m < 10; m++ {n := 1LOOP: if n <= m {fmt.Printf("%dx%d=%d ",n,m,m*n)n++goto LOOP}fmt.Println("")n++}}/*1x1=11x2=2 2x2=41x3=3 2x3=6 3x3=91x4=4 2x4=8 3x4=12 4x4=161x5=5 2x5=10 3x5=15 4x5=20 5x5=251x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=361x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=491x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=641x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81*/
使用 goto 退出多层循环
下面这段代码在满足条件时,需要连续退出两层循环,使用传统的编码方式如下
package mainimport "fmt"func main() {var breakAgain boolfor x := 0; x < 10; x++ {for y := 0; y < 10; y++ {// 满足某个条件时, 退出循环if y == 2 {breakAgain = true // 设置退出标记break // 退出本次循环}}// 根据标记, 还需要退出一次循环if breakAgain { break }}fmt.Println("done")}
将上面的代码使用Go语言的 goto 语句进行优化
package mainimport "fmt"func main() {for x := 0; x < 10; x++ {for y := 0; y < 10; y++ {if y == 2 {// 跳转到标签goto breakHere}}}return // 手动返回, 避免执行进入标签breakHere: // 标签fmt.Println("done")}
使用 goto 集中处理错误
多处错误处理存在代码重复时是非常棘手的,例如:
package mainimport "fmt"func main() {err := firstCheckError() //执行某逻辑,返回错误//如果发生错误,打印错误退出进程if err != nil {fmt.Println(err)exitProcess()return}err = secondCheckError()if err != nil {fmt.Println(err)exitProcess()return}fmt.Println("done")}
在上面代码中,有一部分都是重复的错误处理代码,如果后期在这些代码中添加更多的判断,就需要在这些雷同的代码中依次修改,极易造成疏忽和错误,使用 goto 语句来实现同样的逻辑:
package mainimport "fmt"func main() {err := firstCheckError()if err != nil {goto onExit}err = secondCheckError()if err != nil {goto onExit}fmt.Println("done")return //阻止正常顺序读取到onExitonExit:fmt.Println(err)exitProcess()}


