对命名返回值的修改操作在另外一个协程中执行时,为什么输出返回值时会得到在那个协程中被修改后的值?
最近看到一段代码,大致如下:
package main
import (
"fmt"
"time"
)
var ch = make(chan func())
func doIt() (res int) {
ch <- func() {
res = 3
}
return
}
func main() {
go func() {
for {
time.Sleep(1 * time.Second)
(<-ch)()
}
}()
fmt.Println(doIt())
}
运行之后,控制台的输出结果如下:
(base) rex@MacBook-Pro func % go run named_return_val.go
3
(base) rex@MacBook-Pro func %
其表现出来的结果为:程序阻塞了一秒钟,然后输出数字3。
然而,根据命名返回值方法的定义,定义了命名返回值时,相当于在函数体内第一行声明了该变量,此时该变量具有默认的零值。
另外,doIt
函数内部写入channel ch
的匿名函数在另外一个协程中在一秒钟之后执行,主协程并没有等待其他协程,为什么最后输出结果是3
而不是0
?
我的go版本:
(base) rex@MacBook-Pro func % go version
go version go1.15 darwin/amd64
与
time.Sleep
关系不大,关键是全局无缓冲匿名函数通道ch
读写间接导致groutine
上下文切换 。主协程并非没有等待其它协程,调用
doIt
函数,ch
写操作时阻塞了,这样写你可能会明白输出