在Go语言中,多值赋值时,什么时候会进行值的复制?

huangapple go评论73阅读模式
英文:

In Go, when are values copied in multivalue assignments?

问题

考虑以下Go函数(playground),该函数在Go 1.8中进行了评估:

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

  // 实际上,在这里`i`将始终为0。
  return i, <-c // 返回1, true
}

正如注释中所述,该函数似乎总是在c产生值之后才复制i。由于这发生在遇到返回语句后约1秒钟,这不是我预期的结果。

如果在返回中反转值的顺序,行为仍然相同,如果将返回替换为赋值,行为也相同。

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

因此,问题是这是否是可以依赖的预期行为?在接收操作符的规范部分中,并没有明确说明在这种情况下它会阻塞线程的时间。

英文:

Consider the following Go function (playground), which was evaluated with Go 1.8:

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

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

As stated in the comments, the function seem to always copy i after c has yielded a value. As this happens ~1s after encountering the return statement, this is not what I expected.

The behavior is the same if the value order is reversed in the return and also if the return is replaced by assignment.

Note that I'm not claiming this behavior to be wrong - just unexpected. In fact, this will almost always be what you want to happen.

The question therefore is if this intended/specified behavior that can be relied on?

The spec section on the receive operator doesn't state exactly when it blocks the thread in cases like this.

答案1

得分: 1

根据Go语言规范中关于"求值顺序"的规定,函数和接收操作在这样的语句中是从左到右进行求值的:

例如,在以下(函数局部的)赋值语句中:

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

函数调用和通信的顺序是 f()h()i()j()<-cg()k()然而,这些事件与 x 的求值和索引以及 y 的求值的顺序没有指定。

但正如强调的句子所述,变量求值的顺序没有指定。

该规范还给出了另一个例子,更加清楚地说明了这一点:

a := 1
f := func() int { a++; return a }
x := []int{a, f()}
// x 可能是 [1, 2] 或 [2, 2]:a 和 f() 的求值顺序没有指定

因此,虽然行为是符合预期的,但遗憾的是它没有被指定,并且不能依赖于它。

英文:

According to the spec section on order of evaluation, functions and receive operations in a statement like this are evaluated from left to right:

> 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(), &lt;-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.

But as stated in the emphasized sentence, the order of variable evaluation is not specified.

The section gives another example that makes this even clearer:

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

So while the behavior is as desired, it is unfortunately not specified and cannot be relied on.

huangapple
  • 本文由 发表于 2017年7月10日 15:28:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/45006089.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定