Golang defer關(guān)鍵字的執(zhí)行順序 結(jié)合棧結(jié)構(gòu)解釋延遲調(diào)用機(jī)制

defer在go中的執(zhí)行順序是后進(jìn)先出(lifo),1.遇到defer語句時(shí),函數(shù)調(diào)用會(huì)被壓入中,2.當(dāng)前函數(shù)返回前,棧頂?shù)膁efer函數(shù)依次彈出執(zhí)行;例如連續(xù)兩個(gè)defer,后寫的先執(zhí)行。defer參數(shù)在注冊時(shí)求值,如i++不影響已保存的值。return前會(huì)執(zhí)行defer,可能影響命名返回值的結(jié)果。注意事項(xiàng)包括:避免循環(huán)中頻繁使用defer、不在defer中做耗時(shí)操作、注意作用域及副作用。

Golang defer關(guān)鍵字的執(zhí)行順序 結(jié)合棧結(jié)構(gòu)解釋延遲調(diào)用機(jī)制

golang 中,defer 是一個(gè)非常實(shí)用的關(guān)鍵字,用來延遲執(zhí)行某個(gè)函數(shù)調(diào)用,通常用于資源釋放、鎖的釋放等場景。但很多人剛接觸時(shí)會(huì)對其執(zhí)行順序感到困惑,尤其是當(dāng)多個(gè) defer 出現(xiàn)的時(shí)候。

Golang defer關(guān)鍵字的執(zhí)行順序 結(jié)合棧結(jié)構(gòu)解釋延遲調(diào)用機(jī)制

其實(shí),只要理解 defer 的底層機(jī)制是基于棧結(jié)構(gòu)實(shí)現(xiàn)的,它的執(zhí)行順序就很容易理解了。

Golang defer關(guān)鍵字的執(zhí)行順序 結(jié)合棧結(jié)構(gòu)解釋延遲調(diào)用機(jī)制


defer 的執(zhí)行順序是后進(jìn)先出(LIFO)

Golang 在遇到 defer 語句時(shí),并不會(huì)立即執(zhí)行對應(yīng)的函數(shù),而是將其壓入一個(gè)函數(shù)調(diào)用棧中。等到當(dāng)前函數(shù)即將返回之前,才會(huì)從棧頂開始依次彈出并執(zhí)行這些被推遲的函數(shù)調(diào)用。

立即學(xué)習(xí)go語言免費(fèi)學(xué)習(xí)筆記(深入)”;

舉個(gè)簡單的例子:

Golang defer關(guān)鍵字的執(zhí)行順序 結(jié)合棧結(jié)構(gòu)解釋延遲調(diào)用機(jī)制

func main() {     defer fmt.Println("first")     defer fmt.Println("second")     fmt.Println("hello world") }

輸出結(jié)果是:

hello world second first

雖然兩個(gè) defer 是按順序?qū)懙模捎谒鼈儽粔喝霔V校瑘?zhí)行順序就是反過來的。這和我們?nèi)粘@斫獾摹白詈髮懙南葓?zhí)行”是一致的。


defer 與函數(shù)參數(shù)求值時(shí)機(jī)

一個(gè)容易忽略的細(xì)節(jié)是:defer 后面的函數(shù)參數(shù)是在 defer 被執(zhí)行時(shí)就完成求值的,而不是等到真正執(zhí)行該函數(shù)時(shí)才計(jì)算。

看個(gè)例子:

func demo() {     i := 0     defer fmt.Println(i)     i++ }

這段代碼輸出的是 0,不是 1。因?yàn)?i 的值在 defer 執(zhí)行時(shí)就已經(jīng)確定為 0 了,后續(xù)的 i++ 并不會(huì)影響已經(jīng)保存下來的值。

所以記住一點(diǎn):defer 注冊時(shí)就完成了參數(shù)求值


defer 與 return 的關(guān)系

很多人以為 return 之后就不能再執(zhí)行 defer 了,實(shí)際上并不是這樣。Go 在函數(shù)返回前,會(huì)先處理所有注冊好的 defer 調(diào)用,然后再真正退出函數(shù)。

例如:

func f() int {     var i int     defer func() {         i++     }()     return i }

這個(gè)函數(shù)返回的其實(shí)是 1,而不是 0。因?yàn)?return i 的值已經(jīng)被準(zhǔn)備好了,但在返回前執(zhí)行了 defer,修改了 i 的值。

這種情況說明:defer 可以影響帶命名返回值的函數(shù)的結(jié)果


使用 defer 的一些注意事項(xiàng)

  • 不要在循環(huán)中頻繁使用 defer,可能會(huì)導(dǎo)致性能問題。
  • 避免在 defer 中做耗時(shí)操作,因?yàn)樗鼤?huì)影響函數(shù)的返回速度。
  • defer 的作用域是函數(shù)級別的,不能跨函數(shù)傳遞。
  • 如果 defer 函數(shù)有副作用(比如修改變量),要特別小心它的執(zhí)行順序。

總的來說,理解 defer 的執(zhí)行順序并不難,關(guān)鍵在于它背后的“棧結(jié)構(gòu)”機(jī)制。掌握了這一點(diǎn),很多看似奇怪的行為其實(shí)都合情合理。

基本上就這些,不復(fù)雜但容易忽略。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊15 分享