一個朋友跑來問我一下這段代碼,我覺得很有趣,涉及到的知識點挺多的,所以想談談這段代碼。
話不多說,上代碼:
// 注:這段代碼來自《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函數的參數
其實在我另外一篇文章
中提到過這個問題。對於上面那段代碼,第二個defer
中recover()
作爲log.Printl()
的參數,這種情況下recover()
會在聲明的時候立刻就執行了。這樣做得原因是被延遲的函數是log.Printl()
,對於log.Printl()
他需要立刻知道所要的參數是什麼,那麼如果參數是函數,就應該先執行函數,並把結果傳遞給log.Printl()
函數。
2. defer會忽略函數的返回值
這個無需多說,defer忽略的參數的原因也很簡單。如果一個函數的返回結果在接下來需要用到的話,那麼無需推遲到最後運行,應該立即得到結果,方面後繼的處理。
3. 捕獲函數recover只有在延遲函數調用內直接調用纔會終止錯誤,否則只會返回nil。
首先明確一點,recover()函數的作用就是爲了來捕捉錯誤的,其返回值就是來判斷是否有錯誤捕獲。直接defer這個recover()函數,那麼其返回值直接背忽略,recover()函數就失去了其本身該有的意義。所以這個延遲調用的recover()函數並不會捕獲panic。這也就解釋了上面代碼第三個defer()無法捕獲panic的原因。
撩我?
搜我公衆號:kyda