一文詳解go的defer和return的執(zhí)行順序
詳解go的defer和return的執(zhí)行順序
go的defer和return是golang中的兩個關鍵字,return用于返回函數的返回值,也可以參與一定的流程控制,比如下面代碼,return短路了后面的輸出
package main import "fmt" // defer 和 return的詳解 func main() { foo(2) foo(1) } func foo(i int) { fmt.Println(i) if i == 1 { return } fmt.Println(i + 1) }
結果:
2
3
1
第一次輸出完整的輸出了i和i+1,第二次輸出被短路,只輸出了1
defer是golang中的延遲調用,經常用于文件流的關閉,鎖的解鎖操作,defer后面的操作會在當前函數或者goroutine結束之后進行調用
package main import "fmt" // defer 和 return的詳解 func main() { foo() } func foo() { defer fmt.Println("println defer") fmt.Println("println foo") } 輸出: println foo println defer
defer自身有一些特性,比如defer和defer之間的執(zhí)行順序是先進后出,先defer的最后執(zhí)行,分析下面代碼:
package main import "fmt" // defer 和 return的詳解 func main() { foo() } func foo() { defer fmt.Println("floor 3") defer fmt.Println("floor 2") fmt.Println("floor 1") } 輸出: floor 1 floor 2 floor 3
根據這一特性,如果我們defer調用的代碼中存在panic 的可能性,為了保證系統(tǒng)的運行,我們應該在前面recover而不是后面
ackage main import "fmt" // defer 和 return的詳解 func main() { foo() } func foo() { defer func() { panic("panic test") }() defer func() { if err := recover(); err != nil { fmt.Println("catch panic:", err) } }() } 輸出: panic: panic test
package main import "fmt" // defer 和 return的詳解 func main() { foo() } func foo() { defer func() { if err := recover(); err != nil { fmt.Println("catch panic:", err) } }() defer func() { panic("panic test") }() } 輸出: catch panic: panic test
defer和return的相互影響
defer和return的相互影響,主要是在返回值上表現,考慮下面代碼,輸出應該是什么:
import "fmt" // defer 和 return的詳解 func main() { fmt.Println(foo1()) fmt.Println(foo2()) fmt.Println(foo3()) } func foo1() int { i := 1 defer func() { i++ }() return i } func foo2() (i int) { i = 1 defer func() { i++ }() return i } func foo3() (i int) { defer func() { i++ }() return 1 }
輸出:
1
2
2
導致上面情況的原因是
在 foo1
函數中,defer
語句中的閉包會在函數返回后執(zhí)行,但是此時返回值已經確定為 1
,所以最終返回 1
。
在 foo2
函數中,使用了命名返回值 i
。defer
語句中的閉包修改的是這個命名返回值,所以返回 2
。
在 foo3
函數中,同樣使用了命名返回值 i
,defer
語句中的閉包修改了這個命名返回值,并且函數直接返回 1
,但 defer
中的修改使得最終返回 2
。
而return的另一個特性,也會影響return和defer中代碼的執(zhí)行順序
package main import "fmt" // defer 和 return的詳解 func main() { fmt.Println(foo1()) } func foo1() int { defer func() { fmt.Println("This is defer") }() return func() int { fmt.Println("This is return") return 1 }() } 輸出: This is return This is defer 1
導致上面輸出的原因是,return是非原子性的,defer會在return返回值之前執(zhí)行,但return中的語句,會被全部執(zhí)行,直到return錨定了某個值或者命名返回值,然后執(zhí)行defer語句,最后返回return錨定的這個值
到此這篇關于一文詳解go的defer和return的執(zhí)行順序的文章就介紹到這了,更多相關go defer和return執(zhí)行順序內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang記錄、計算函數執(zhí)行耗時、運行時間的一個簡單方法
這篇文章主要介紹了Golang記錄、計算函數執(zhí)行耗時、運行時間的一個簡單方法,本文直接給出代碼實例,需要的朋友可以參考下2015-07-07