zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    架构设计的UML图形思考
    SymmetricDS文档翻译--【Chapter 3. 具体配置(Configuration)[section C]】
    LeetCodeOJ. String to Integer (atoi)
    jquery05 继承
    jquery 04
    jquery constructor(null)
    jquery js解析函数、函数直接调用
    jquery init 关系
    jquery constructor
    jQuery03
  • 原文地址:https://www.cnblogs.com/Kingram/p/14548529.html
Copyright © 2011-2022 走看看