golang defer未按预期顺序执行 原因分析 解决方案

在golang项目开发中,使用到了defer,代码举例如下:

func sum(i string, a, b int) int {
    ret := a + b
    fmt.Println(i)
    return ret
}


func main() {
    a := 1
    b := 2
    defer sum("1", a, sum("2", a, b))
    defer sum("3", a, b)
}

  

按照期望,defer先进后出的原则,应该是先打印出最后一个defer函数的值:

3

再打印第一个defer函数的值:

2

但实际打印是:

2

3

1

即第一个defer函数中的sum("2", a, b)最先被执行了,而不是我们想象中的只要是属于defer函数的内容都要等待执行。

 

 

 


经过资料查找和测试,可以确定:当defer被声明时,其参数就会被实时解析,

我们通过以下代码来解释这条规则:

func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

  



运行结果是0


这是因为虽然我们在defer后面定义的是一个带变量的函数: fmt.Println(i). 但这个变量(i)在defer被声明的时候,就已经确定其值了。

这也是为什么本案例中的示例代码会先执行sum("2", a, b)了,效果是这样的:

tmp := sum("2", a, b)
defer sum("1", a, tmp)

  

 

解决方案


defer声明时,确保此时其参数的正确性,不使用不确定的变量作为入参。