這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一、defer 關鍵字工作原則
1. A deferred function's arguments are evaluated when the defer statement is evaluated.
func a() { i := 0 defer fmt.Println(i) i++ return}
defer 函數中的變數 i 在 defer 函數被定義的時候就已經明確,值為0。隨後 defer 之外的 i++ 並不會影響 defer 函數列印的,所以列印結果為:0。
2.Deferred function calls are executed in Last In First Out order after the surrounding function returns.
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) }}
多個 defer 函數被調用的順序遵循 後進先出 的原則,所以列印結果為:3210。
3.Deferred functions may read and assign to the returning function's named return values.
func c() (i int) { defer func() { i++ }() return 1}
defer 函數可以讀取並賦值給外部函數的命名傳回值。所以函數 c 的傳回值為:2。
二、defer return 執行流程
func f0() (r int) { t := 5 defer func() { fmt.Printf("f0 defer t is :%d", t)//5 fmt.Printf("f0 defer r is :%d", r)//5 t = t + 5 fmt.Printf("f0 defer r is :%d", r)//5 }() return t}
這裡需要注意的是,return xxx語句並不是一條原子指令,defer 被插入到了 賦值 與 ret 之間。因此 return t應該被拆解程兩部分,r = t 和 return。
這樣 f0 函數可以被改造成下面的函數
func f0() (r int) { t := 5 r = t defer func() { fmt.Printf("f0 defer t is :%d", t)//5 fmt.Printf("f0 defer r is :%d", r)//5 t = t + 5 fmt.Printf("f0 defer r is :%d", r)//5 }() return}
最終函數 f0 的傳回值為:5。
三、思維實驗
func f1() (r int) { defer func(r int) { fmt.Printf("f1 defer r is:%d", r)//0 r = r + 5 fmt.Printf("f1 defer2 r is:%d", r)//5 }(r) fmt.Printf("f1 r is:%d", r)//0 return 1}
函數返回結果:1。(defer 三原則、值傳遞、return xxx 拆解)
func f2() (r int) { defer func() { fmt.Printf("f2 defer r is:%d", r)//1 r = r + 5 fmt.Printf("f2 defer2 r is:%d", r)//6 }() fmt.Printf("f2 r is:%d", r)//0 return 1}
函數返回結果為:6。(refer 三原則、return xxx 拆解)
參考資料
Defer, Panic, and Recover
Defer statements