Skip to content

Go循环控制 ​

阅读提示

  • 适用版本:Go 1.21+(示例在 Go 1.22 下验证;循环变量语义在 Go 1.22 前后不同)· 前置知识:条件控制 · 阅读时长:约 6 分钟

在 Go 中,有仅有一种循环语句:for,Go 抛弃了while语句,for语句可以被当作while来使用。

for ​

语句格式如下

go
for init statement; expression; post statement {
  execute statement
}

当只保留循环条件时,就变成了while。

go
for expression {
  execute statement
}

这是一个死循环,永远也不会退出

go
for {
  execute statement
}

示例

这是一段输出[0,20]区间数字的代码

go
for i := 0; i <= 20; i++ {
    fmt.Println(i)
}

你可以同时初始化多个变量,然后将其递增

go
for i, j := 1, 2; i < 100 && j < 1000; i, j = i+1, j+1 {
  fmt.Println(i, j)
}

当成while来使用

go
num := 1
for num < 100 {
    num *= 2
}

双循环打印九九乘法表,这是一个很经典的循环案例

go
func main() {
  for i := 1; i <= 9; i++ {
    for j := 1; j <= 9; j++ {
      if i <= j {
        fmt.Printf("%d*%d = %2d  ", i, j, i*j)
      }
    }
    fmt.Println()
  }
}

输出如下

go
1*1 =  1  1*2 =  2  1*3 =  3  1*4 =  4  1*5 =  5  1*6 =  6  1*7 =  7  1*8 =  8  1*9 =  9
2*2 =  4  2*3 =  6  2*4 =  8  2*5 = 10  2*6 = 12  2*7 = 14  2*8 = 16  2*9 = 18
3*3 =  9  3*4 = 12  3*5 = 15  3*6 = 18  3*7 = 21  3*8 = 24  3*9 = 27
4*4 = 16  4*5 = 20  4*6 = 24  4*7 = 28  4*8 = 32  4*9 = 36
5*5 = 25  5*6 = 30  5*7 = 35  5*8 = 40  5*9 = 45
6*6 = 36  6*7 = 42  6*8 = 48  6*9 = 54
7*7 = 49  7*8 = 56  7*9 = 63
8*8 = 64  8*9 = 72
9*9 = 81

for range ​

for range可以更加方便的遍历一些可迭代的数据结构,如数组,切片,字符串,映射表,通道。语句格式如下:

go
for index, value := range iterable {
  // body
}

index为可迭代数据结构的索引,value则是对应索引下的值,例如使用for range遍历一个字符串。

go
func main() {
   sequence := "hello world"
   for index, value := range sequence {
      fmt.Println(index, value)
   }
}

for range也可以迭代一个整型值,字面量,常量,变量都是有效的。

go
for i := range 10 {
    fmt.Println(i)
}

n := 10
for i := range n {
    fmt.Println(i)
}

const n = 10
for i := range n {
  fmt.Println(i)
}

对于每一个种数据结构,for range的实现都有所不同,后续也会讲到,你可以前往Go - for statement以了解更多细节。

break ​

break关键字会终止最内层的for循环,结合标签一起使用可以达到终止外层循环的效果,例子如下:这是一个双循环

go
func main() {
  for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
      if i <= j {
        break
      }
      fmt.Println(i, j)
    }
  }
}

输出

1 0
2 0
2 1
3 0
3 1
3 2
...
9 6
9 7
9 8

使用标签来中断外层循环

go
func main() {
Outer:
  for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
      if i <= j {
        break Outer
      }
      fmt.Println(i, j)
    }
  }
}

输出

continue ​

continue关键字会跳过最内层循环的本次迭代,直接进入下一次迭代,结合标签使用可以达到跳过外层循环的效果,例子如下

go
func main() {
  for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
      if i > j {
        continue
      }
      fmt.Println(i, j)
    }
  }
}

输出

0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
...
7 7
7 8
7 9
8 8
8 9
9 9

使用标签

go
func main() {
Out:
  for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
      if i > j {
        continue Out
      }
            fmt.Println(i, j)
    }
  }
}

输出

0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9

完整示例 ​

下面的程序可以直接运行:复制到文件后执行 go run main.go,或粘贴到 Go Playground 运行。

go
package main

import "fmt"

func main() {
	// 经典三段式 for
	sum := 0
	for i := 0; i < 5; i++ {
		sum += i
	}

	// while 风格的 for
	n := 1
	for n < 100 {
		n *= 3
	}

	// 无限循环 + break
	count := 0
	for {
		count++
		if count == 3 {
			break
		}
	}

	// 标签:从内层循环 continue 外层循环
	pairs := 0
outer:
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			if j == 1 {
				continue outer
			}
			pairs++
		}
	}

	fmt.Println(sum, n, count, pairs)

	// range 遍历切片:返回下标与元素副本
	nums := []int{10, 20, 30}
	for i, v := range nums {
		fmt.Println(i, v)
	}

	// range 遍历字符串按 rune 迭代,下标是字节偏移
	for i, r := range "a中" {
		fmt.Printf("%d:%c\n", i, r)
	}
}

预期输出:

text
10 243 3 3
0 10
1 20
2 30
0:a
1:中

常见错误与踩坑 ​

  • for 的三个部分都可以省略。 for { } 是无限循环;for n < 100 { } 可当作 while 使用。
  • range 拿到的是元素副本。 修改 v 不会改变切片元素——遍历 []struct 时最常踩这个坑。
  • range 字符串按 rune 迭代而不是字节。 下标会跳跃(如 1:中),而 len 仍然是字节长度。
  • 循环变量捕获语义在 Go 1.22 有变化。 1.22 起每次迭代都是新变量;旧版本在闭包捕获时需写 v := v。
  • break 与 continue 只作用于最内层循环。 跳出多层循环需要配合标签。

更新记录 ​

  • 2026-10-14:新增"阅读提示"、完整可运行示例(含预期输出)、常见错误与踩坑清单,以及本更新记录。