for {}是go原生唯一的无限循环语法,省略初始化、条件和后置操作,非语法糖;比for true {}更稳妥,适用于阻塞等待、信号监听等场景。

Go里for {}就是最简无限循环,不是语法糖也不是特殊形式
它就是for语句省略了初始化、条件判断和后置操作三部分的合法写法,编译器不额外处理,底层就是跳转指令。别把它想成类似while true的变体——Go没有while,for {}就是唯一的、原生的无限循环表达方式。
常见错误是写成for ; ; {},虽然能运行,但纯属冗余;也有人误以为要加空格或换行才能生效,其实for{} (无空格)完全合法。
- 所有Go版本都支持,从1.0到1.22无兼容性问题
- 不会比
for true {}更快,但少一次布尔求值,汇编层面略简洁 - IDE和
go fmt会自动格式化为for {},不必手动对齐分号
什么时候必须用for {}而不是for true {}
主要出现在需要阻塞等待、不希望被编译器优化掉的场景,比如主goroutine守着程序不退出,或信号监听循环。
for true {}在某些极端优化级别下(如-gcflags="-l"禁用内联+死代码消除)可能被误判为不可达逻辑,而for {}明确告诉编译器“这里就是要死循环”,更稳妥。
立即学习“go语言免费学习笔记(深入)”;
- 服务启动后主协程:启动HTTP服务器后,
for {}防止main函数返回 - 信号监听:配合
signal.Notify,循环里select等待os.Interrupt - 嵌入式或系统编程中,避免因常量折叠导致意外退出
break和continue在for {}里的行为和普通循环完全一致
别担心它“太简单”就失去控制力——break跳出当前for {},continue直接跳到下一轮(也就是立刻再次进入循环体)。它们不依赖条件表达式,只依赖显式控制流。
容易踩的坑是忘记break出口,尤其在select里没写default又没case匹配时,for {}会卡死:
for {
select {
case <-done:
break // ❌ 这里只跳出select,不是for!
}
// 会一直执行到这里,无限循环
}
正确写法是用带标签的break:
loop:
for {
select {
case <-done:
break loop
}
}
和select {}的区别:一个真忙等,一个真挂起
for {}是CPU密集型空转,会吃满一个核;select {}是永久阻塞,不消耗CPU。两者目的不同,不能混用。
常见误用是想“暂停程序”就写for {},结果上线后发现某个goroutine把CPU跑满。这时候该用select {}或time.Sleep。
- 后台任务协调、状态轮询等需要主动检查的逻辑 → 用
for {}+time.Sleep或select带超时 - 纯粹等待外部事件(信号、通道关闭、定时器)→ 优先用
select {}或带case的select - 调试时临时卡住程序?
select {}比for {}更安全,不伤机器
真正难的是判断“该不该主动轮询”——这取决于你等的是同步信号还是异步事件。轮询通道读取?大概率设计错了;轮询文件是否存在?那可能是合理场景。










