天天看點

Go語言中defer語句使用小結一、defer語句執行時機二、多個defer語句的執行順序是逆序執行三、defer與panic四、return實作邏輯總結:defer、 return、傳回值三者順序

Go語言中defer語句使用小結

defer是Go語言中的延遲執行語句,用來添加函數結束時執行的代碼,常用于釋放某些已配置設定的資源、關閉資料庫連接配接、斷開socket連接配接、解鎖一個加鎖的資源。Go語言機制擔保一定會執行defer語句中的代碼。其它語言中也有類似的機制,比如Java、C#語言裡的finally語句,C++語言裡的析構函數(Destructor)可以起類似的作用,C++語言機制擔保在對象被銷毀前一定會執行析構函數中的代碼。C++中的析構函數析構的是對象,Go中的defer析構的是函數。

文章目錄

    • Go語言中defer語句使用小結
  • 一、defer語句執行時機
  • 二、多個defer語句的執行順序是逆序執行
  • 三、defer與panic
    • 1.defer與panic
    • 2.在panic語句前的defer語句會被執行
  • 四、return實作邏輯
  • 總結:defer、 return、傳回值三者順序

一、defer語句執行時機

defer語句在函數傳回之前 或者 函數中 return語句(return語句可能調用另一個函數) 之後執行。示例代碼:

package main
 
import (
    "fmt"
)
 
func main() {
    fmt.Println(deferReturn())
}
 
func deferReturn() (ret int) {
    defer func() {
        ret++
    }()
    return 10
}
           

上述代碼列印出來的值是:11。 defer語句 匿名函數中的“ret++” 對傳回值 10 加 1 變成了 11。再來看一個defer語句出現在return語句之後的代碼:

func returnDefer() (ret int) {
    return 0
    defer func() {
        ret++
        ret++
    }()
    return 1
}

           

上述returnDefer函數的傳回值是:0。原因是defer語句還沒有添加上代碼執行到"return 0"函數就傳回了,是以defer語句就沒有執行。

二、多個defer語句的執行順序是逆序執行

當出現多條 defer 語句時以逆序執行(類似棧,即後進先出)。示例代碼:

func deferSample() {
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d ", i)
    }
}
           

上述代碼将會輸出:4 3 2 1 0

三、defer與panic

1.defer與panic

代碼如下(示例):

func panicDefer() {
    panic("panic")
    defer fmt.Println("defer after panic")
}
           

上述代碼的輸出如下:

panic: panic

goroutine 1 [running]:
main.panicDefer()
    E:/godemo/testdefer.go:17 +0x39
main.main()
    E:/godemo/testdefer.go:13 +0x20

           

可以看到 defer 語句沒有執行。

2.在panic語句前的defer語句會被執行

示例代碼

func deferPanic() {
defer fmt.Println("defer before panic")
 panic("panic")
}

           

上述代碼輸出如下:

defer before panic
panic: panic

goroutine 1 [running]:
main.deferPanic()
    E:/godemo/testdefer.go:19 +0x95
main.main()
    E:/godemo/testdefer.go:14 +0x20

Process finished with exit code 2
           

Go中的panic類似其它語言中的抛出異常,panic後面的代碼不再執行(panic語句前面的defer語句會被執行)。

四、return實作邏輯

1、第一步給傳回值指派(若是有名傳回值直接指派,匿名傳回值 則 先聲明再 指派) ;

2、第二步調用RET傳回指令并傳入傳回值,RET會檢查是否存在defer語句,若存 在就先逆序插播 defer語句 ;

3、最後 RET 攜帶傳回值退出函數 。

可以看出 ,return 不是一個原子操作,函數傳回值與 RET 傳回值并不一定一緻。

總結:defer、 return、傳回值三者順序

defer、 return、傳回值 三者的執行順序是 : return 最先給傳回值指派;接着 defer 開始執行一些收尾工作;最後 RET 指令攜帶傳回值退出函數。

繼續閱讀