Go 语言 for 是唯一循环结构,支持三段式、条件式和无限循环三种语义;三段式需分号分隔,初始化变量作用域限于 for 块内,条件在每次迭代前判断,后置语句在循环体后执行。
Go 语言的 for 是唯一循环结构,没有 while 或 do-while,但通过不同写法能覆盖所有常见循环场景。关键不是“有多少种写法”,而是每种写法对应什么语义、何时该用、以及哪些地方容易出错。
这是最接近传统编程语言的写法,适合需要明确初始化、条件判断和后置操作的计数循环。
for 后面三个表达式必须用分号 ; 分隔,不能省略或改用逗号i := 0)作用域仅限于该 for 块内false,立即退出i++)在本轮循环体执行完后、下轮条件判断前执行for i := 0; i < 5; i++ {
fmt.Println(i)
}当不确定迭代次数,只依赖内部逻辑控制退出时,直接省略中间的条件表达式,形成无限循环。必须在循环体内用 break 显式跳出,否则会死循环。
for ;; 或更常见的 for(Go 允许完全省略三部分)for ; ; 以外的形式,比如 for true 是语法错误——Go 不接受布尔字面量作条件for {
line, err := reader.ReadString('\n')
if err != nil {
break
}
process(line)
}range 是 Go 中最常用、也最容易误用的循环形式。它不是语法糖,而是编译器生成的特定迭代逻辑,行为因目标类型而异。
range 返回索引和元素值(值是副本),修改元素变量不影响原切片range
range 按 rune(而非 byte)迭代,适合处理 Unicodedata := []int{1, 2, 3}
for i, v := range data {
data[i] = v * 2 // 必须用索引赋值才生效
}Go 不支持带标签的 goto 跳转到任意位置,但允许给 for 加标签,配合 break 或 continue 实现跨层控制流。这在处理嵌套循环搜索或状态机时很实用。
for 语句前(不能换行)break 会直接跳出对应标签的循环,不是当前层continue 会跳到对应标签循环的下一次迭代开始处for、switch 或 select)outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break oute
r
}
fmt.Printf("i=%d,j=%d ", i, j)
}
}真正要注意的不是“写法数量”,而是每种形式背后的数据所有权(值拷贝 vs 引用)、迭代时机(前置判断还是后置判断)、以及是否隐含阻塞(如 range 读 channel)。写错一个分号、漏掉一个 break,或者误以为 range 返回的是指针,都可能引发静默 bug。