深入理解Go中defer的機制
defer
是 Go 語言中用于延遲執(zhí)行函數(shù)調(diào)用的關(guān)鍵字,常用于資源清理(如關(guān)閉文件、釋放鎖)和異常處理。但其行為機制存在一些隱蔽的細(xì)節(jié),稍有不慎可能導(dǎo)致難以察覺的 Bug。本文通過多個直觀示例,深入剖析 defer
的核心機制。
一、defer 的執(zhí)行順序:后進先出(LIFO)
多個 defer
語句按逆序執(zhí)行,類似于棧的“后進先出”原則。
示例 :多個 defer 的執(zhí)行順序
func main() { defer fmt.Println("defer 1") defer fmt.Println("defer 2") fmt.Println("main 邏輯") }
輸出:
main 邏輯
defer 2
defer 1
結(jié)論:
defer
語句按注冊順序的逆序執(zhí)行,確保依賴資源按正確順序釋放(如先打開的文件后關(guān)閉)。
二、defer 的參數(shù)預(yù)計算:值拷貝的陷阱
defer
的參數(shù)在注冊時即被預(yù)計算并拷貝,而非執(zhí)行時動態(tài)獲取。
示例 :參數(shù)預(yù)計算的影響
func main() { x := 10 defer fmt.Println("defer 中的 x:", x) // x 的值在注冊時被拷貝 x = 20 fmt.Println("main 中的 x:", x) }
輸出:
main 中的 x: 20
defer 中的 x: 10
結(jié)論:
- 若參數(shù)是值類型(如
int
、string
),defer
會拷貝當(dāng)前值,后續(xù)修改不影響已注冊的defer
。 - 若參數(shù)是指針或引用類型(如
*int
、slice
),拷貝的是地址,后續(xù)修改會影響defer
的執(zhí)行結(jié)果。
三、defer 與閉包:動態(tài)綁定的變量
defer
函數(shù)若使用外部變量(閉包),會引用變量的最新值,而非注冊時的值。
示例 :閉包中的變量綁定
func main() { x := 10 defer func() { fmt.Println("defer 中的 x:", x) // 閉包引用最新值 }() x = 20 fmt.Println("main 中的 x:", x) }
輸出:
main 中的 x: 20
defer 中的 x: 20
結(jié)論:
- 閉包中的變量在
defer
執(zhí)行時才求值,因此會反映變量的最終狀態(tài)。 - 若需固定閉包中的值,需在注冊時通過參數(shù)傳遞(如
defer func(a int) { ... }(x)
)。
四、defer 與返回值:隱式的賦值邏輯
defer
中修改返回值的行為取決于返回值的定義方式(值返回 vs 指針返回)。
示例 4:值返回與指針返回的差異
// 值返回:defer 修改不影響返回值 func f1() int { x := 10 defer func() { x++ }() return x // 實際返回的是 x 的拷貝 } // 指針返回:defer 修改影響返回值 func f2() *int { x := 10 defer func() { x++ }() return &x // 返回 x 的地址 } func main() { fmt.Println(f1()) // 輸出 10 fmt.Println(*f2()) // 輸出 11 }
結(jié)論:
- 值返回:返回值在
return
時被拷貝,defer
修改原變量不影響已拷貝的值。 - 指針返回:返回的是變量地址,
defer
通過地址修改原變量,影響最終結(jié)果。
到此這篇關(guān)于Go中defer的機制的文章就介紹到這了,更多相關(guān)Go defer機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決golang處理http response碰到的問題和需要注意的點
這篇文章主要介紹了解決golang處理http response碰到的問題和需要注意的點,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12Mac下Vs code配置Go語言環(huán)境的詳細(xì)過程
這篇文章給大家介紹Mac下Vs code配置Go語言環(huán)境的詳細(xì)過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07GoRoutines高性能同時進行多個Api調(diào)用實現(xiàn)
這篇文章主要為大家介紹了GoRoutines高性能同時進行多個Api調(diào)用實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03Go泛型實戰(zhàn)教程之如何在結(jié)構(gòu)體中使用泛型
這篇文章主要介紹了Go泛型實戰(zhàn)教程之如何在結(jié)構(gòu)體中使用泛型,根據(jù)Go泛型使用的三步曲提到的:類型參數(shù)化、定義類型約束、類型實例化我們一步步來定義我們的緩存結(jié)構(gòu)體,需要的朋友可以參考下2022-07-07淺談Go語言不提供隱式數(shù)字轉(zhuǎn)換的原因
本文主要介紹了淺談Go語言不提供隱式數(shù)字轉(zhuǎn)換的原因,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03解決Go?Json?Unmarshal反序列化丟失數(shù)字精度問題
業(yè)務(wù)會使用?id生成器?產(chǎn)生的?分布式唯一ID,長度比較長,所以代碼反序列化時,會出現(xiàn)精度丟失問題,那如何解決呢,下面小編就來和大家詳細(xì)講講2023-08-08Golang時間處理庫go-carbon?v2.2.13發(fā)布細(xì)則
這篇文章主要為大家介紹了Golang?時間處理庫go-carbon?v2.2.13發(fā)布細(xì)則,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11