golang中的defer和return的执行顺序


结论

go中是先给return准备返回值,再根据defer先进后出的规则执行,最后将返回值返回给调用者

测试用例1验证分析

代码片段如下:

func foo_1() (err error) {
    defer func() {
        fmt.Println(err)
        err = errors.New("a")
    }()

    defer func(e error) {
        fmt.Println(e)
        e = errors.New("b")
    }(err)

    err = errors.New("c")
    return err
}

func TestDeferAndReturn(t *testing.T) {
    fmt.Println(foo_1())
}

分析:

  • 第一步:函数foo_1()执行到return关键字时,先准备好返回值,err=c
  • 第二步:进入第二个defer函数,这里面进行了值拷贝,将err拷贝给了e,所以这里打印的e是nil,之后将e赋值也是不影响err的值的,err还是c
  • 第三步:进入第一个defer函数,这里先打印了err,还是c,然后对err进行了赋值,err值变为a
  • 第四步:经过defer的操作,现在的err值变为了a,故返回给调用者是a

这个测试用例的输出如下

=== RUN   TestDeferAndReturn

  
  
  
    c a --- PASS: TestDeferAndReturn (0.00s) PASS Process finished with exit code 0 
  

测试用例2验证分析

代码片段如下:

func foo_2() error {
    var err error
    defer func() {
        fmt.Println(err)
        err = errors.New("a")
    }()

    defer func(e error) {
        fmt.Println(e)
        e = errors.New("b")
    }(err)

    err = errors.New("c")
    return err
}

func TestDeferAndReturn(t *testing.T) {
    fmt.Println(foo_2())
}

分析:

这里的返回值是匿名返回写法,这种情况下,return会首先创建一个临时变量temp,然后将err赋值给temp,后续两个defer中对err的操作并不会影响到temp中的值,所以这里返回给调用者的是c

这个测试用例的输出如下

=== RUN   TestDeferAndReturn

  
  
  
    c c --- PASS: TestDeferAndReturn (0.00s) PASS Process finished with exit code 0 
  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM