代码
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
go fmt.Println(<-ch1)
ch1 <- 5
time.Sleep(1 * time.Second)
}
运行结果
以上的代码执行结果为:运行时死锁
正确代码
问题就出在
go fmt.Println(<-ch1)
应该改写成
go func(){
fmt.Println(<-ch1)
}()
原因分析
原因也很简单:
在 Go 语言规范中,关于 go 语句有这么一句描述:
这里说明,go 语句后面的函数调用,其参数会先求值,这和普通的函数调用求值一样。在规范中调用部分是这样描述的:
f(a1, a2, … an)
大意思是说,函数调用之前,实参就被求值好了。
go fmt.Println(<-ch1)<-ch1
更多
defer和go function同理,因此:
defer recover()
这样的代码执行起来是没问题的,但是如果该函数的入参有像channel这种嵌套的routine,就会造成死锁,所以为了培养良好的代码规范,原则上我们还是会写成这样:
defer func() {
recover()
}()