Go语言仅支持for循环,可通过省略初始化和后置语句实现while效果,用range遍历集合更安全,for range中取变量地址需注意副本问题。
Go语言不支持 while 或 do-while 语法,这是语言设计的明确取舍——只保留一个循环结构 for,但它的灵活性足以覆盖所有常见场景。
for 写出等效的 while 循环只需省略初始化和后置语句,只留条件判断即可。这和 C/Java 中的 while 行为完全一致:
i := 0
for i < 5 {
fmt.Println(i)
i++
}for (i —— Go 不允许括号,会报错 syntax error: unexpected (
i 的作用域仅限于该 for 块内,不能在循环外继续使用do-while:先执行、再判断Go 没有内置 do-while,但可以用无限循环 + 条件退出来实现“至少执行一次”:
i := 0
for {
fmt.Println("hello")
i++
if i >= 3 {

break
}
}break 判断之前,确保首次必执行break 或条件写反(如用 == 而非 >=),导致死循环for {} 编译后就是跳转指令,和传统 do-while 生成的汇编几乎一样for 经典形式对切片、map、字符串等,优先用 range,而不是手写索引循环:
// ✅ 推荐:简洁、安全、自动处理中文 rune
for i, v := range slice {
fmt.Println(i, v)
}
// ❌ 不推荐:易越界、难读、对字符串会切错中文
for i := 0; i < len(slice); i++ {
fmt.Println(i, slice[i])
}
string 用 range 是按 rune 遍历,而用索引是按 byte;中文字符可能被截断for range 中取变量地址(如 &v)会得到同一个地址,因为 v 是每次迭代的副本 —— 需要 val := v; &val 才安全for {} 常用于服务器主循环或 goroutine 后台任务,但必须有明确退出路径:
for {
select {
case msg := <-ch:
handle(msg)
case <-done:
return // 优雅退出
}
}break,尤其在嵌套或带 select 的场景中;用 return 或带标签的 break label 更可控go run 会卡住,go build 后运行也会持续占资源time.AfterFunc(10 * time.Second, func(){ os.Exit(1) })
真正容易被忽略的是:看似简单的 for 省略写法,其变量作用域、内存复用行为、以及和 range 的语义差异,都会在并发或长期运行服务中悄悄引发 bug。写之前,先想清楚你到底要“控制条件”,还是“遍历数据”。