go中循环仅用for实现,含三种语法:标准三段式(初始化;条件;后置)、条件式(for 条件)和无限式(for)。标准式最常用于索引遍历,分号分隔三部分,细节易出错。

Go 里没有 while、没有 do-while,所有循环都靠 for 实现——但不是“只有一种写法”,而是三种语法形式对应三类真实需求,写错往往是因为没对齐场景。
标准三段式 for:初始化、条件、后置语句必须用分号隔开
这是最常用于计数或索引遍历的写法,比如遍历切片前 10 个元素、按步长递减等。关键不是“能不能写”,而是分号和括号的细节容易翻车。
for i := 0; i 合法;<code>for (i := 0; i 直接编译失败 —— Go 不接受括号- 初始化语句中声明的变量(如
i)作用域仅限该for块内,循环外访问会报undefined: i - 条件判断发生在每次迭代「开始前」,后置语句(如
i++)在本轮循环体执行完、「下轮条件判断前」运行 - 遍历切片时推荐
i 而非 <code>i ,避免边界越界或漏掉最后一个元素
省略 condition 的 for:模拟 while,但必须手动更新条件变量
当循环次数不确定,比如重试逻辑、等待 channel 数据、轮询状态时,你会自然想到 “while”。Go 的做法是省略中间的条件表达式,但行为不像 C 那样隐含“继续直到条件变假”——它完全依赖你体内更新。
- 写成
for count := 0; count 是错的:中间的 <code>;不能省,否则变成for count := 0; count ,语法不合法 - 更常见的是全省略 init/post:
for ok { doWork(); ok = checkDone() }—— 如果忘了在循环体内改ok,就是死循环 - 性能上无差异,但可读性弱于
for range或带select的事件循环,仅在逻辑强依赖单个布尔状态时才推荐
for range 遍历切片/字符串/map:值是副本,&v 指向同一地址
这是最容易写出 Bug 的地方:你以为在取每个元素的地址,结果所有 &v 都指向同一个内存位置,最终只保留最后一个元素的地址。
- 遍历切片时,
for _, v := range slice中的v是每次迭代的拷贝,修改v不影响原数据;要改原切片,得用索引:for i := range slice { slice[i] *= 2 } - 想存元素地址?别写
ptr := &v,正确写法是ptr := &slice[i],或在循环内声明新变量:val := v; ptr := &val - 遍历字符串时,
value是rune类型;用传统for i := 0; i 会按字节读,中文直接乱码 —— 应转 <code>[]rune(s)或直接用for _, r := range s - 遍历
map顺序不保证,不要依赖输出顺序;且range不是语法糖,底层做了值复制和变量复用,这点在闭包捕获时尤其危险
for {} 无限循环:必须有 break / return / panic,且 select 易阻塞
服务器主循环、后台任务监听、定时器配合 channel 等场景离不开它,但“无限”不等于“随意”,卡死往往发生在最不起眼的分支遗漏上。
-
for {}本身合法,但循环体内必须有退出机制,否则程序启动即卡死,只能Ctrl+C - 典型组合是
for { select { case msg := ,但漏写 <code>default或超时分支(case ),一旦 <code>ch没数据,整个select阻塞,循环停摆 - 需要定时重试时,优先用
time.Ticker+select,而不是time.Sleep后continue—— 后者难以控制精度且易被信号中断 - 嵌套循环中若需跳出外层,要用带标签的
break outer,普通break只作用于最近一层
真正难的不是记住语法,而是每次写 for 前问自己一句:这个循环的终止条件由谁控制?变量生命周期是否符合预期?那个被反复赋值的 v,此刻到底指向哪块内存?
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











