You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go多值返回中表达式求值顺序是否符合语言规范?

Go多值返回的求值顺序问题

问题背景

《Go语言规范》中明确给出示例:切片和map赋值时,原语与函数调用的求值顺序未被指定,但规范未提及多值返回场景,因此存在疑问:该规则是否适用于多值返回的表达式?

规范示例代码:

a := 1
f := func() int { a++; return a }
x := []int{a, f()}            // x可能为[1, 2]或[2, 2]:a与f()的求值顺序未指定
m := map[int]int{a: 1, a: 2}  // m可能为{2: 1}或{2: 2}:两个map赋值的求值顺序未指定
n := map[int]int{a: f()}      // n可能为{2: 3}或{3: 3}:键与值的求值顺序未指定

核心疑问

疑问1:多值返回的表达式求值顺序是否未指定?

如下函数的返回结果是否存在两种可能?

func run() (int, int) {
    a := 1
    f := func() int { a++; return a }
    return a, f() // 始终返回1,2?始终返回2,2?还是两种都可能?
}

疑问2:依赖求值顺序的代码是否存在风险?

若求值顺序未指定,如下代码可能因编译器更新在未来出现问题:

func CountRows(ctx context.Context, db *pgxpool.Pool) (int, error) {
  row := db.QueryRow(ctx, "SELECT COUNT(*)")
  var count int
  return count, row.Scan(&count)
}

原始问题

不清楚Go语言规范是否明确说明函数返回值是逐个求值返回,还是所有表达式求值完成后统一返回。如下代码是否能保证始终输出10 <nil>,还是可能输出0 <nil>?

package main

import "fmt"

func main() {
    fmt.Println(run())
    // Output: 10 <nil>
}

func run() (int, error) {
    var i int
    return i, inc(&i)
}

func inc(i *int) error {
    *i = *i + 10
    return nil
}

结论

根据Go语言规范及相关讨论:

  • 多值返回语句中,各返回表达式的求值顺序未被规范指定,编译器可以按任意顺序求值这些表达式。
  • 第一个run()函数的返回结果可能是1,2也可能是2,2,两种情况均符合规范要求。
  • 原始问题中的代码,当前Go playground输出10 <nil>是因为编译器先求值inc(&i)再求值i,但规范不保证这个顺序,未来编译器更新后可能出现0 <nil>的结果。
  • 类似CountRows的代码存在风险,因为row.Scan(&count)修改count后,count的求值顺序不确定,可能返回未被修改的初始值0。

依赖未指定的求值顺序编写代码是不安全的,应避免这种写法,确保代码逻辑不依赖求值顺序。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 01:57:37