考虑以下使用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语句后〜1s发生这种情况,所以这不是我期望的。

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

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

因此,问题是是否可以依靠这种预期/指定的行为?

在这种情况下,receive operator上的spec部分未明确说明何时阻塞线程。

最佳答案

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

例如,在(本地函数)分配中

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 may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
因此,虽然行为是所需的,但遗憾的是未指定行为,因此无法依赖。

10-04 16:56