Golang运算符优先级容易出错的地方

9次阅读

Go 中 && 和 || 优先级低于 ==、!= 等比较运算符,而位运算符 &、|、^ 优先级介于比较与逻辑之间;赋值运算右结合但不支持链式;++/– 仅为语句不可用于表达式。

Golang 运算符优先级容易出错的地方

Go 里 &&||==!= 优先级高?错的

这是最常被误记的一点:很多人凭 C/Java 经验以为逻辑与 / 或优先级高于比较,但在 Go 中,&&|| 的优先级 ** 低于 ** 所有比较运算符(==!=>= 等)。这意味着 a == b && c != d 不需要括号也能按预期分组,但一旦混入位运算或赋值,就容易翻车。

真正危险的是和 &|^ 这些位运算符混用——它们的优先级比 && 高,但比 == 低。比如:

if a & b == c {……}

这实际等价于 if a & (b == c) {……},而 b == c 是布尔值,不能参与位与,编译直接报错:invalid operation: a & (b == c) (mismatched types int and bool)

  • 遇到 &|^ 和比较运算符共存,必须加括号明确意图,如 (a & b) == c
  • && / || 可以放心和比较连写,无需括号;但和位运算、移位(>>)一起时,务必查优先级表
  • Go 官方优先级共 5 级,其中位运算(&^|)和算术运算同级(第 4 级),比较是第 3 级,逻辑是第 2 级

赋值运算符 =+= 的右结合性容易引发误解

Go 中赋值是右结合的,a = b = c 合法吗?不合法——因为 b = c 返回的是 c 的值,但 a = (b = c) 要求 b = c 有可寻址结果,而它只是语句,不是表达式。所以 a = b = c 编译失败:cannot assign to b = c

立即学习 go 语言免费学习笔记(深入)”;

但复合赋值如 a += b += c 更隐蔽:

a, b, c := 1, 2, 3 a += b += c // 编译错误:invalid operation: b += c (no addressable left-hand side)

原因:复合赋值要求左操作数必须是“可寻址的”(addressable),而 b += c 本身不是变量,无法作为 a += …… 的右操作数。

  • Go 不支持链式赋值,x = y = zx += y += z 全部非法
  • 若想模拟,必须拆成两行:y += z; x += y
  • 注意 := 是声明 + 赋值,不能出现在表达式中,f(x := 1) 直接语法错误

++-- 不是运算符,不能用于表达式

Go 里 ++-- 是语句,不是表达式级运算符。这意味着你不能写 a = b++if x-- > 0arr[i++] = v —— 全部编译报错:syntax error: unexpected ++cannot use x-- as value

常见误写场景:

// ❌ 错误 for i := 0; i // ✅ 正确写法:先用再加,或后加再用 for i := 0; i 
  • ++/-- 只能单独成句,后面不能跟分号以外的符号
  • 函数调用参数、数组索引、返回值位置等一切需要“值”的地方,都不能出现 ++/--
  • 想实现类似 C 的效果,必须拆成两步:val := arr[i]; i++

类型断言 .(T) 和方法调用 .Method() 的结合顺序

当对一个接口值做类型断言后再调用方法,比如 obj.(Stringer).String(),看起来没问题,但若 obj 实际不是 Stringer,运行时 panic。更隐蔽的问题是结合了逻辑运算:

if obj.(Stringer).String() != "" && obj != nil { ……}

这段代码会在 obj 不是 Stringer 时直接 panic,根本不会执行 obj != nil 判断——因为 . 的优先级高于 &&,整个左边先求值。

  • 类型断言失败是运行时 panic,无法用 && 短路规避
  • 安全写法是先用「带 ok 的断言」:if s, ok := obj.(Stringer); ok && s.String() != ""
  • 记住:.(成员访问)、->(C 风格)、[](索引)、()(调用)都是最高优先级,且左结合;它们会最先绑定

Go 的运算符优先级表很短,但出错往往不在“记不住”,而在“凭经验套其他语言”。尤其位运算、赋值、类型断言这几处,编译器报错信息未必直指根源,得看清楚哪部分被优先绑定了。

text=ZqhQzanResources