defer、panic、recover

一個朋友跑來問我一下這段代碼,我覺得很有趣,涉及到的知識點挺多的,所以想談談這段代碼。
話不多說,上代碼:

// 注:這段代碼來自《go語言學習筆記》
func catch() {
	log.Printl("catch:", recover())
}

func main() {
	defer catch()
	defer log.Printl(recover())
	defer recover()
	
	panic("i am dead")
}

(可以試着不要看運行結果,自己想想運行結果是怎麼樣的,幫助加深印象)

結果:

<nil>
catch: i am dead

我相信大多數剛學完基礎的朋友遇到上面這道題都會做錯。如果做對了,也可以看看下面的分析,看看自己有沒有分析對。如果對了,恭喜。如果錯了,沒關係,跟着我分析一下,避免在實際中寫出這種坑爹的代碼。

這段代碼主要涉及到三個方面的知識點:

1. 一個函數作爲被defer函數的參數
其實在我另外一篇文章
中提到過這個問題。對於上面那段代碼,第二個deferrecover()作爲log.Printl()的參數,這種情況下recover()會在聲明的時候立刻就執行了。這樣做得原因是被延遲的函數是log.Printl(),對於log.Printl()他需要立刻知道所要的參數是什麼,那麼如果參數是函數,就應該先執行函數,並把結果傳遞給log.Printl()函數。

2. defer會忽略函數的返回值
這個無需多說,defer忽略的參數的原因也很簡單。如果一個函數的返回結果在接下來需要用到的話,那麼無需推遲到最後運行,應該立即得到結果,方面後繼的處理。

3. 捕獲函數recover只有在延遲函數調用內直接調用纔會終止錯誤,否則只會返回nil。
首先明確一點,recover()函數的作用就是爲了來捕捉錯誤的,其返回值就是來判斷是否有錯誤捕獲。直接defer這個recover()函數,那麼其返回值直接背忽略,recover()函數就失去了其本身該有的意義。所以這個延遲調用的recover()函數並不會捕獲panic。這也就解釋了上面代碼第三個defer()無法捕獲panic的原因。

撩我?
搜我公衆號:kyda
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章