詳解Go中defer與return的執(zhí)行順序
示例
直接上代碼
func test() int { result = 123 defer func() { result = 456 }() return result } func main() { fmt.Println(test()) }
結(jié)果
123
修改之后的代碼
func test() (result int) { result = 123 defer func() { result = 456 }() return result } func main() { fmt.Println(test()) }
結(jié)果
456
再看下面這個(gè)例子
func test() (result int) { result = 123 defer func() { fmt.Println("aaa") result = 456 }() return func() int { fmt.Println("bbb") return result }() } func main() { fmt.Println(test()) }
結(jié)果
bbb
aaa
456
defer與return哪個(gè)先執(zhí)行
這個(gè)問題主要是defer 與return哪個(gè)先執(zhí)行。很容易理解如果一個(gè)函數(shù)中有多個(gè)defer,它是棧的形式保存的,執(zhí)行的時(shí)候先從棧頂執(zhí)行,即后面定義的defer會(huì)先被執(zhí)行,并且defer是在return執(zhí)行之后才執(zhí)行的。
因?yàn)閐efer是在return 執(zhí)行之后才執(zhí)行的,所以第三個(gè)例子中先打印bbb后打印aaa很好理解。
第二個(gè)例子和第三個(gè)例子test函數(shù)返回456也好理解,因?yàn)閐efer可以改變返回值中定義的變量。雖然return已經(jīng)返回了,defer還是可以改變它。
第一個(gè)例子,defer改變的不是返回值中定義的變量,而是局部變量,這個(gè)時(shí)候return已經(jīng)執(zhí)行了,defer改變局部變量沒有用。在defer中改變局部變量的值沒有效果。第一個(gè)例子return result是值拷貝,即將result的值拷貝一份并返回,因此defer改變r(jià)esult并不會(huì)影響返回值。
第二、第三例子中return返回的result不是值拷貝,因?yàn)閞esult是在返回值中定義的變量,所以return返回的直接是那個(gè)變量,這個(gè)時(shí)候沒有值拷貝
再看看下面這個(gè)例子
func test() *int { result := 123 defer func() { result = 456 }() return &result } func main() { fmt.Println(*test()) }
結(jié)果
456
這個(gè)時(shí)候defer改變局部變量result又生效了,這是為什么?是因?yàn)閞eturn 返回的是局部變量的地址,而不是局部變量的只拷貝。因此在defer中修改局部遍歷會(huì)影響返回結(jié)果。
總結(jié)
上面描述可能有點(diǎn)繞,需要親自實(shí)驗(yàn)一下,仔細(xì)理解才能真正搞懂。下面總結(jié)一下我的理解:
return 返回有2種方式:
值拷貝:將局部變量的值拷貝到返回值上。return 直接返回局部變量的值(不是局部變量的引用)
非值拷貝:即return 返回值的時(shí)候沒有發(fā)生值拷貝,有兩種情況:
- 將返回值中定義的變量返回。
- 將局部變量的引用返回。
非值拷貝的情況下,defer修改返回值是生效的。
return 的執(zhí)行其實(shí)用兩步驟:1.先將return的結(jié)果賦值到返回值上;2.再將返回值賦值作為函數(shù)的結(jié)果賦值給調(diào)用者。
defer的執(zhí)行是在return的兩步驟中間執(zhí)行的。所以return如果發(fā)生了值拷貝則defer不會(huì)改變返回結(jié)果;如果return沒有發(fā)生值拷貝則defer會(huì)改變返回結(jié)果。
到此這篇關(guān)于詳解Go中defer與return的執(zhí)行順序的文章就介紹到這了,更多相關(guān)Go defer return內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go開發(fā)Gin項(xiàng)目添加jwt功能實(shí)例詳解
這篇文章主要為大家介紹了Go開發(fā)Gin項(xiàng)目中添加jwt功能實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07GoLang bytes.Buffer基礎(chǔ)使用方法詳解
Go標(biāo)準(zhǔn)庫中的bytes.Buffer(下文用Buffer表示)類似于一個(gè)FIFO的隊(duì)列,它是一個(gè)流式字節(jié)緩沖區(qū),我們可以持續(xù)向Buffer尾部寫入數(shù)據(jù),從Buffer頭部讀取數(shù)據(jù)。當(dāng)Buffer內(nèi)部空間不足以滿足寫入數(shù)據(jù)的大小時(shí),會(huì)自動(dòng)擴(kuò)容2023-03-035個(gè)可以在Golang中優(yōu)化代碼以提高性能的技巧分享
作為一名軟件工程師,確保你的代碼高效且性能良好是非常重要的。本文主要和大家分享5個(gè)可以在Golang中優(yōu)化代碼以提高性能的技巧,希望對大家有所幫助2023-03-03Go?1.21新內(nèi)置函數(shù)min、max和clear的用法詳解
Go?1.21?版本已經(jīng)正式發(fā)布,它帶來了許多新特性和改進(jìn),其中引入了的三個(gè)新內(nèi)置函數(shù):max、min?和?clear,接下來我們就來看看這些函數(shù)的用途和特點(diǎn)吧2023-08-08Golang timer可能造成的內(nèi)存泄漏問題分析
本文探討了Golang中timer可能造成的內(nèi)存泄漏問題,通過分析一段代碼,解釋了為什么協(xié)程在調(diào)用timer.Stop()后無法正常退出,文章指出,timer.Stop()并不關(guān)閉Channel,導(dǎo)致協(xié)程無法繼續(xù)執(zhí)行,最后,提出了一種修復(fù)方法,并呼吁大家關(guān)注和分享2024-12-12