一、defer作用
Go語言的defer關鍵字提供了一種延遲執行機制,它能確保指定的函數調用在當前函數返回前被執行。這一特性常用于資源釋放和異常處理場景。
二、defer基本特性
(1)執行時機:defer 語句會在外層函數返回前執行,無論函數是正常返回還是因 panic 而異常終止。
(2)執行順序:多個 defer 語句按后進先出(LIFO)的順序執行,類似于棧的操作方式。
(3)參數求值:defer 語句的參數在注冊時就已完成求值,而非執行時才進行計算。
三、defer機制
1)參數綁定時機
在defer
語句中,參數值會在聲明時立即確定。代碼示例如下:
func main() {a := 10// 輸出10defer fmt.Println("defer a:", a) a = 20// 輸出20fmt.Println("current a:", a)
}
參數a
的值在defer
語句出現時就已經固定,運行結果如下:
2)執行順序
執行順序遵循后進先出(LIFO)原則,最后注冊的defer語句將最先執行。代碼示例如下:
func main() {defer fmt.Println("first")defer fmt.Println("second")defer fmt.Println("third")
}
執行如果如下:
3)修改返回值
defer 語句能夠修改具名返回值,但對匿名返回值無效。代碼示例如下:
func main() {defer fmt.Println(deferFuncReturn())
}func deferFuncReturn() (result int) {i := 1defer func() { result++ }()// 實際返回2return i
}
執行如果如下:
四、應用場景
1)資源釋放
確保正確釋放文件、鎖等資源。代碼示例如下:
file, err := os.Open("test.txt")
if err != nil { return err
}defer file.Close()
2)鎖管理
避免忘記解鎖導致的死鎖,代碼示例如下:
mu.Lock()
defer mu.Unlock()
3)異常恢復
與recover配合捕獲panic異常,代碼示例如下:
defer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r)}
}()
4)事務處理
確保數據庫事務正確提交或回滾,代碼示例如下:
tx, err := db.Begin()defer func() {if p := recover(); p != nil {tx.Rollback()}
}()
5)性能監控
記錄函數執行時間,代碼示例如下:
func doWork() {start := time.Now()defer func() {fmt.Printf("耗時: %v\n", time.Since(start))}()
}
五、defer使用注意事項
1)避免在循環中使用defer
,可能導致資源未及時釋放。
2)對于高頻調用的簡單操作,建議手動釋放資源而非使用defer
。
3)os.Exit()
等強制退出方式會跳過defer
的執行。
4)defer
中的錯誤容易被忽略,需要特別關注錯誤處理。