文章目錄
- Go defer關鍵字
Go defer關鍵字
Go語言的defer會在目前函數傳回前執行傳入的函數,經常用于關閉檔案描述符,關閉資料庫連接配接等資源回收工作。
Go中defer主要有兩個問題:
- defer調用時機和調用順序
- defer調用函數使用傳值方式傳遞參數會進行預運算,計算結果會發生改變,最終進行計算的參數是運作時的結果
關于調用時機和調用順序
func main() {
fmt.Println("開始執行main函數")
for i := 0;i < 5;i++{
defer fmt.Println("執行defer,i=",i)
}
fmt.Println("main函數結束")
}
結果:

調用時機:main函數執行完後,defer邏輯才開始執行
defer調用順序:先進後出,壓棧規則,先開始的defer後執行
func main() {
fmt.Println("main start")
{
fmt.Println("代碼塊start")
defer fmt.Println("代碼塊中defer")
fmt.Println("代碼塊end")
}
fmt.Println("main end")
}
結果:
即使出現代碼塊,defer的作用域也是等整個函數結束後才執行
func main() {
num := 0
fmt.Println("main start")
defer fmt.Println(num)
num = 2
fmt.Println("main end")
}
結果:
defer不會再執行時才會拷貝函數的參數值,而是一開始就會拷貝函數的參數值,是以這裡并不會得到2
func main() {
startTime := time.Now()
fmt.Println("main start")
defer func() {
fmt.Println(time.Since(startTime))
}()
// main函數執行時間3秒
time.Sleep(3 * time.Second)
fmt.Println("main end")
}
結果:
defer這裡是因為閉包,閉包擷取變量拷貝的是位址,而不是參數值
總結:defer調用的函數,參數的值在defer定義時就确定了,但如果值是位址,需要等到運作時才知道具體指向的值
func main() {
num := 0
fmt.Println("main start")
defer fmt.Println(num)
fmt.Println("main end")
os.Exit(0) // 執行os、Exit後,defer不會執行
}