詳解Go中defer與return的執(zhí)行順序
示例
直接上代碼
func test() int { result = 123 defer func() { result = 456 }() return result } func main() { fmt.Println(test()) }
結果
123
修改之后的代碼
func test() (result int) { result = 123 defer func() { result = 456 }() return result } func main() { fmt.Println(test()) }
結果
456
再看下面這個例子
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()) }
結果
bbb
aaa
456
defer與return哪個先執(zhí)行
這個問題主要是defer 與return哪個先執(zhí)行。很容易理解如果一個函數(shù)中有多個defer,它是棧的形式保存的,執(zhí)行的時候先從棧頂執(zhí)行,即后面定義的defer會先被執(zhí)行,并且defer是在return執(zhí)行之后才執(zhí)行的。
因為defer是在return 執(zhí)行之后才執(zhí)行的,所以第三個例子中先打印bbb后打印aaa很好理解。
第二個例子和第三個例子test函數(shù)返回456也好理解,因為defer可以改變返回值中定義的變量。雖然return已經返回了,defer還是可以改變它。
第一個例子,defer改變的不是返回值中定義的變量,而是局部變量,這個時候return已經執(zhí)行了,defer改變局部變量沒有用。在defer中改變局部變量的值沒有效果。第一個例子return result是值拷貝,即將result的值拷貝一份并返回,因此defer改變result并不會影響返回值。
第二、第三例子中return返回的result不是值拷貝,因為result是在返回值中定義的變量,所以return返回的直接是那個變量,這個時候沒有值拷貝
再看看下面這個例子
func test() *int { result := 123 defer func() { result = 456 }() return &result } func main() { fmt.Println(*test()) }
結果
456
這個時候defer改變局部變量result又生效了,這是為什么?是因為return 返回的是局部變量的地址,而不是局部變量的只拷貝。因此在defer中修改局部遍歷會影響返回結果。
總結
上面描述可能有點繞,需要親自實驗一下,仔細理解才能真正搞懂。下面總結一下我的理解:
return 返回有2種方式:
值拷貝:將局部變量的值拷貝到返回值上。return 直接返回局部變量的值(不是局部變量的引用)
非值拷貝:即return 返回值的時候沒有發(fā)生值拷貝,有兩種情況:
- 將返回值中定義的變量返回。
- 將局部變量的引用返回。
非值拷貝的情況下,defer修改返回值是生效的。
return 的執(zhí)行其實用兩步驟:1.先將return的結果賦值到返回值上;2.再將返回值賦值作為函數(shù)的結果賦值給調用者。
defer的執(zhí)行是在return的兩步驟中間執(zhí)行的。所以return如果發(fā)生了值拷貝則defer不會改變返回結果;如果return沒有發(fā)生值拷貝則defer會改變返回結果。
到此這篇關于詳解Go中defer與return的執(zhí)行順序的文章就介紹到這了,更多相關Go defer return內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
5個可以在Golang中優(yōu)化代碼以提高性能的技巧分享
作為一名軟件工程師,確保你的代碼高效且性能良好是非常重要的。本文主要和大家分享5個可以在Golang中優(yōu)化代碼以提高性能的技巧,希望對大家有所幫助2023-03-03Go?1.21新內置函數(shù)min、max和clear的用法詳解
Go?1.21?版本已經正式發(fā)布,它帶來了許多新特性和改進,其中引入了的三個新內置函數(shù):max、min?和?clear,接下來我們就來看看這些函數(shù)的用途和特點吧2023-08-08