权限位掩码必须用1ULL或1U左移定义,以确保无符号固定宽度类型,避免32位系统下左移溢出导致未定义行为;所有权限常量须声明为uint64_t或uint32_t,禁用int或宏定义。

权限位掩码必须用 1 ,不能直接用 <code>iota
直接写 Read = iota 会得到 0、1、2……这不是合法的位掩码。0 在按位或中无效,1 和 2 的二进制是 01 和 10,但 3(即 1 | 2)等于 011,而如果 Execute = iota 得到 2,那 Read | Write 就等于 Execute,逻辑全乱。
正确做法是强制每位独立:
Read = 1 → 值为 <code>1(0001)-
Write隐式继承表达式 →1 = <code>2(0010) -
Execute→1 = <code>4(0100) - 所有值二进制只有一位为 1,
|不重叠,&可精准检测
同一 const 块里混用字符串常量会重置 iota 行计数
很多人在权限定义中间加一句 Version = "v1.2",结果后面所有标志值全偏移 —— 因为 iota 是按“带赋值的行”计数,字符串常量不参与 iota 递增,但它占了一行,下一行的 iota 值已+1,而没人接住它。
避免方式:
立即学习“go语言免费学习笔记(深入)”;
- 权限常量和版本/描述字符串分开放在不同
const块 - 若必须同块,把字符串放最前或最后,不插在中间
- 用下划线
_ = "comment"占位时也要小心:它不消耗iota,但仍是新行,后续隐式赋值仍会继承已递增的iota
iota 是编译期行索引,不是“用了几次就加几次”
它的值取决于在 const 块中**实际发生赋值的行序号**,空行、注释、_ 都不触发递增,但它们会让下一行的行号变大,而 iota 值 = 当前行在块内的有效赋值行序(从 0 开始)。
典型踩坑场景:
- 写
// debug only注释后跟Delete,结果Delete值比预期大 1 - 同一行写
A, B = iota, iota→ A 和 B 都是当前iota值,只算一次递增 - 跨
const块必然重置:const (X = iota)和const (Y = iota)中 X、Y 都是 0
给枚举加 String() 方法时类型声明不能省
如果只写 Pending = iota,常量是 untyped int;但实现 String() 必须绑定到具名类型,比如 type Permission uint,再写 Pending Permission = iota。
否则会出现:
- 传参时隐式转换失败(如函数接收
Permission类型,却传入未声明类型的Pending) -
switch分支漏掉default,非法值(如网络传入99)返回空字符串,日志里看不到线索 -
json.Marshal仍输出数字而非字符串,要改需额外实现MarshalJSON()
真正难的不是写对第一行,而是确保整个常量块的行序、类型绑定、位运算语义和序列化行为全部对齐 —— 少一个约束,线上就可能出 silent bug。


















