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