iota是Go编译器在const块中按行遍历ValueSpec时维护的行号计数器,从0开始,每处理一行自增1,仅在遇到新const时重置;它不是运行时变量,不占内存,编译期即替换为整数值。
iota 每行 +1 不是因为“语法规定要这样”,而是编译器在解析 const 块时,按行遍历常量声明语句(ValueSpec)并为每个名字生成常量对象时,同步递增的一个内部计数器。它的本质是 const 块内「当前处理到的第几行」的索引,从 0 开始,仅在遇到新 const 关键字时重置。
Go 编译器在处理 const 块时,并不真正“运行”代码,而是在 AST(抽象语法树)构建阶段扫描所有 ValueSpec 节点。每个 ValueSpec 对应一行常量声明(哪怕该行有多个名字,如 a, b, c = iota, iota, iota),编译器会为其中每个名字调用类似 NewConst(name, itoa) 的逻辑 —— 这里的 itoa 就是 iota 的底层变量名,它随每处理完一个 ValueSpec 自增 1。
关键点:
_ 的行,只要构成一个 ValueSpec(哪怕没有名字或值),iota 就会推进ValueSpec)因为 Go 的 const 声明粒度是 ValueSpec,不是单个标识符。例如:
const (
a, b = iota, iota // ← 一个 ValueSpec,iota 值为 0
c // ← 另一个 ValueSpec,iota 值为 1
)
这里只有两行声明,所以 iota 分别是 0 和 1,而不是 0、0、1。编译器不会把 a 和 b 拆成两个独立的常量声明节点;它们共享同一行上下文和同一个 iota 值。
这也解释了简写行为:
b 没写等号右边?继承上一个非空 ValueSpec 的右表达式(即 iota)像 1 这类写法之所以常用,是因为它把“行号”直接映射为二进制位权:
1 → 1(二进制 0001)
1 → 2(二进制 0010)
1 → 4(二进制 0100)
这种模式天然适合定义互斥的状态位(如 mutexLocked, mutexWoken),每一行代表一个独立 bit,避免手动计算 1/2/4/8 容易出错。
iota 只在遇到 const 关键字时归零,与作用域、函数、包无关。这

这个设计让 iota 的行为完全可预测:你数一数 const 括号里有多少个 ValueSpec(即多少行有效声明),就能准确说出每个 iota 出现时的值。