在 Go 中,什么时候在多值赋值中复制值?

In Go, when are values copied in multivalue assignments?

考虑以下使用 Go 1.8 评估的 Go 函数 (playground):

func f() (int, bool) {
  i := 0
  c := make(chan bool)
  go func() {
    time.Sleep(1 * time.Second)
    i = 1
    c <- true
  }()

  // In practice, `i` will always be 0 here.
  return i, <-c // returns 1, true
}

如评论中所述,该函数似乎总是在i c 产生一个值之后复制。由于在遇到 return 语句后约 1 秒发生这种情况,这不是我所期望的。

如果在 return 中颠倒值顺序并且 return 被赋值替换,则行为相同。

请注意,我并不是说这种行为是错误的——只是出乎意料。事实上,这几乎总是你想要发生的事情。

因此,问题是这种 intended/specified 行为是否值得信赖?

receive operator 的规范部分没有准确说明在这种情况下它何时会阻塞线程。

根据 order of evaluation 的规范部分,像这样的语句中的函数和接收操作是从左到右求值的:

For example, in the (function-local) assignment

y[f()], ok = g(h(), i()+x[j()], <-c), k()

the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.

但是正如强调句中所说,变量求值的顺序没有规定。

本节给出了另一个例子,使这一点更加清晰:

a := 1
f := func() int { a++; return a }
x := []int{a, f()}
// x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified

因此,尽管行为符合要求,但遗憾的是未指定且不能依赖。