Go语言defer详解
1. 使用defer的優(yōu)勢
defer一般用于資源的釋放和異常的捕捉, 作為Go語言的特性之一.
defer 語句會將其后面跟隨的語句進(jìn)行延遲處理. 意思就是說 跟在defer后面的語言 將會在程序進(jìn)行最后的return之后再執(zhí)行.
在 defer 歸屬的函數(shù)即將返回時,將延遲處理的語句按 defer 的逆序進(jìn)行執(zhí)行,也就是說,先被 defer 的語句最后被執(zhí)行,最后被 defer 的語句,最先被執(zhí)行。
1.1 資源的釋放
一般我們寫讀取文件的代碼如下
func CopyFile(dstName, srcName string) (written int64, err error) {src, err := os.Open(srcName)if err != nil {return}dst, err := os.Create(dstName)if err != nil {return }dst.Close()src.Close()return }在程序最開始,os.Open及os.Create打開了兩個文件資源描述符,并在最后通過file.Close方法得到釋放,在正常情況下,該程序能正常運(yùn)行,一旦在dstName文件創(chuàng)建過程中出現(xiàn)錯誤,程序就直接返回,src資源將得不到釋放。因此需要在所有錯誤退出時釋放資源,即修改為如下代碼才能保證其在異常情況下的正確性。
即在每個err里面如果發(fā)生了異常, 要及時關(guān)閉src的資源.
這個問題出現(xiàn)在加鎖中也非常常見
但是這樣做未免太麻煩了, defer優(yōu)雅的幫我們解決了這個問題
比如我們可以這樣
這樣寫的話, 就不需要在每個異常處理塊中都加上Close() 或者 unlock()語句了
1.2 異常的捕捉
程序在運(yùn)行時可能在任意的地方發(fā)生panic異常,例如算術(shù)除0錯誤、內(nèi)存無效訪問、數(shù)組越界等,這些錯誤會導(dǎo)致程序異常退出。在很多時候,我們希望能夠捕獲這樣的錯誤,同時希望程序能夠繼續(xù)正常執(zhí)行。一些語言采用try…catch語法,當(dāng)try塊中發(fā)生異常時,可以通過catch塊捕獲。
Go語言使用了特別的方式處理這一問題。defer的特性是無論后續(xù)函數(shù)的執(zhí)行路徑如何以及是否發(fā)生了panic,在函數(shù)結(jié)束后一定會得到執(zhí)行,這為異常捕獲提供了很好的時機(jī)。異常捕獲通常結(jié)合recover函數(shù)一起使用。
如上所示,在executePanic函數(shù)中,手動執(zhí)行panic函數(shù)觸發(fā)了異常。當(dāng)異常觸發(fā)后,函數(shù)仍然會調(diào)用defer中的函數(shù),然后異常退出。輸出如下,表明調(diào)用了defer中的函數(shù),并且main函數(shù)將不能正常運(yùn)行,程序異常退出打印出棧追蹤信息。
如下所示,當(dāng)在defer函數(shù)中使用recover進(jìn)行異常捕獲后,程序?qū)⒉粫惓M顺?#xff0c;并且能夠執(zhí)行正常的函數(shù)流程。如下輸出表明,盡管有panic,main函數(shù)仍然在正常執(zhí)行后退出。
使用了recover函數(shù)后, 程序?qū)⒉粫惓M顺? 仍會正常執(zhí)行
2. 多個defer語句的執(zhí)行順序
當(dāng)有多個 defer 行為被注冊時,它們會以逆序執(zhí)行(類似棧,即后進(jìn)先出), 相當(dāng)于開辟了一個延時調(diào)用棧
func main() {fmt.Println("defer begin")// 將defer放入延遲調(diào)用棧defer fmt.Println(1)defer fmt.Println(2)// 最后一個放入, 位于棧頂, 最先調(diào)用defer fmt.Println(3)fmt.Println("defer end") }執(zhí)行的結(jié)果就是
// 先打印正常語句 defer begin defer end // 然后按從上到下的順序執(zhí)行defer調(diào)用棧中的語句 3 2 1總結(jié)
以上是生活随笔為你收集整理的Go语言defer详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go中的Map实现机制
- 下一篇: Go中线程和协程的区别