Go中表达式产生值、语句执行动作不返回值;i++是语句故不可用于赋值右边,须拆为取值再自增,以此规避求值顺序歧义。

Go 语言中,语句和表达式有本质区别:**表达式产生值,语句执行动作但不返回值**。这不是语法细节,而是影响你能否写出合法、可读、无歧义代码的关键分水岭。
为什么 i++ 不能写在赋值右边?
因为 ++ 和 -- 在 Go 中是语句,不是表达式——它不返回任何值。这和 C/C++/Java 完全不同。
-
i++是一条独立语句,作用是“让i自增 1”,没有返回值 -
j := i++会报错:invalid operation: i++ (non-name i)或更直白的syntax error: unexpected ++ - 想实现类似效果,必须拆成两步:
i := 0 j := i // 先取值 i++ // 再自增
- 这个设计是为了避免
f(i++, i++)这类求值顺序未定义的陷阱,Go 直接不让它存在
哪些东西是表达式?哪些是语句?一眼识别法
判断标准很简单:**能不能放在 = 右边、if 条件里、函数调用参数中?能,就是表达式;不能,大概率是语句。**
- ✅ 表达式(可求值):
42、x + y、len(s)、strings.ToUpper("go")、m["key"]、&v - ❌ 语句(只执行):
if x > 0 { ... }、for i := 0; i 、return err、var s string、i++ - ⚠️ 特殊注意:
defer f()、go f()、select {...}都是语句,哪怕它们内部包含函数调用(f()是表达式,但整个go f()不是)
方法调用:为什么有时能赋值,有时不能?
方法调用是否属于表达式,取决于它是否返回值,以及你用的是 method value 还是 method expression:
立即学习“go语言免费学习笔记(深入)”;
-
obj.Method()是表达式(如果Method有返回值),可以赋值:s := user.GetName() // 合法,GetName() 返回 string
-
(*T).Method是函数值(表达式),可赋给变量或传参:f := (*User).Save f(&user, db) // 合法
- 但
user.Save()本身只是语句(如果Save返回error且你没接收):user.Save() // 语句;若忽略 error,属危险操作
- 常见坑:把带副作用的方法(如
json.Unmarshal)当纯表达式用,却忘了它要传指针且可能失败
最易被忽略的一点:Go 的 if 和 switch 支持「短变量声明」,比如 if x := getValue(); x > 0 { ... }——这里的 x := getValue() 是语句,而 x > 0 才是表达式。很多人误以为整行都是表达式,结果在 for 初始化部分写 for x := 0; x 时,下意识想写成 for x := getValue(); x > 0; x++,却忘了中间分号后只能是布尔表达式,不能是语句。










