結論
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