
`|=`是go语言中的位或赋值运算符,用于对变量执行按位或(or)操作后将结果原地赋值给该变量,等价于`a = a | b`,常用于标志位(flag)的累积设置。
在Go中,|=属于复合赋值运算符(compound assignment operator),其语义为:将左操作数与右操作数进行按位或运算,并将结果直接写回左操作数。它并非逻辑或(||),而是底层的位级操作,适用于整数类型(如uint、int、uint32等),尤其在状态标记、权限组合、模式配置等场景中极为高效。
以你提供的代码为例:
func getPageInfoMode(r *http.Request) (mode PageInfoMode) {
for _, k := range strings.Split(r.FormValue("m"), ",") {
if m, found := modeNames[strings.TrimSpace(k)]; found {
mode |= m // 关键行:将当前模式标志 m 累加到 mode 中
}
}
return
}此处 PageInfoMode 很可能是一个基于整型的自定义类型(如 type PageInfoMode uint8),而 modeNames 是一个映射字符串到位标志的字典,例如:
var modeNames = map[string]PageInfoMode{
"summary": 1 << iota, // 0001
"detail", // 0010
"chart", // 0100
"export", // 1000
}当请求参数为 m=summary,detail 时,循环会依次执行:
立即学习“go语言免费学习笔记(深入)”;
- mode |= summary → mode = 0001
- mode |= detail → mode = 0001 | 0010 = 0011
最终 mode 的二进制值同时包含多个启用的标志位,后续可通过位运算快速判断(如 mode&summary != 0)或清除(如 mode &^= detail)特定选项。
⚠️ 注意事项:
- |= 要求左右操作数类型必须严格一致(或可隐式转换),且必须为整数类型;对布尔、浮点或结构体使用会导致编译错误。
- 它不适用于切片、map 或指针解引用(除非指针指向整数且显式取值)。
- 与 += 等算术复合运算符不同,|= 无溢出风险,但需确保位宽足够容纳所有组合(推荐使用 uint32 或 uint64 配合 iota 定义标志)。
- 若需原子性更新(如并发环境),应配合 sync/atomic 包的 atomic.OrUint32 等函数,而非直接使用 |=。
总结:|= 是Go中简洁、高效、语义清晰的位操作利器,体现了Go对系统编程特性的务实支持。合理运用它,能让标志管理代码更安全、更紧凑、更具可读性。









