代码

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()
}()