前言
Golang中的defer是使用頻次比較高的,能創造出延遲生效特效的一種方式。
defer也有自己的矯情,需要注意的。 本文將從通過程式碼的方式來說明defer的三點矯情。
1.defer的生效順序 2.defer與return,函式返回值之間的順序 3.defer定義和執行兩個步驟,做的事情。
正文
1.defer的生效順序
先說結論:defer的執行順序是倒序執行(同入棧先進後出)
func main() {
defer func() {
fmt.Println("我後出來")
}()
defer func() {
fmt.Println("我先出來")
}()
}
複製程式碼
執行後列印出:
我先出來
我後出來
複製程式碼
2.defer與return,函式返回值之間的順序
先說結論:return最先執行->return負責將結果寫入返回值中->接著defer開始執行一些收尾工作->最後函式攜帶當前返回值退出
返回值的表達方式,我們知道根據是否提前宣告有兩種方式:一種是func test() int 另一種是 func test() (i int),所以兩種情況都來說說
func test() int
func main() {
fmt.Println("main:", test())
}
func test() int {
var i int
defer func() {
i++
fmt.Println("defer2的值:", i)
}()
defer func() {
i++
fmt.Println("defer1的值:", i)
}()
return i
}
複製程式碼
輸出:
defer1的值: 1
defer2的值: 2
main: 0
複製程式碼
詳解:return的時候已經先將返回值給定義下來了,就是0,由於i是在函式內部宣告所以即使在defer中進行了++操作,也不會影響return的時候做的決定。
func test() (i int)
func main() {
fmt.Println("main:", test())
}
func test() (i int) {
defer func() {
i++
fmt.Println("defer2的值:", i)
}()
defer func() {
i++
fmt.Println("defer1的值:", i)
}()
return i
}
複製程式碼
輸出:
defer1的值: 1
defer2的值: 2
main: 2
複製程式碼
詳解:由於返回值提前宣告瞭,所以在return的時候決定的返回值還是0,但是後面兩個defer執行後進行了兩次++,將i的值變為2,待defer執行完後,函式將i值進行了返回。
3.defer定義和執行兩個步驟,做的事情
先說結論:會先將defer後函式的引數部分的值(或者地址)給先下來【你可以理解為()裡頭的會先確定】,後面函式執行完,才會執行defer後函式的{}中的邏輯
func test(i *int) int {
return *i
}
func main(){
var i = 1
// defer定義的時候test(&i)的值就已經定了,是1,後面就不會變了
defer fmt.Println("i1 =" , test(&i))
i++
// defer定義的時候test(&i)的值就已經定了,是2,後面就不會變了
defer fmt.Println("i2 =" , test(&i))
// defer定義的時候,i就已經確定了是一個指標型別,地址上的值變了,這裡跟著變
defer func(i *int) {
fmt.Println("i3 =" , *i)
}(&i)
// defer定義的時候i的值就已經定了,是2,後面就不會變了
defer func(i int) {
//defer 在定義的時候就定了
fmt.Println("i4 =" , i)
}(i)
defer func() {
// 地址,所以後續跟著變
var c = &i
fmt.Println("i5 =" , *c)
}()
// 執行了 i=11 後才呼叫,此時i值已是11
defer func() {
fmt.Println("i6 =" , i)
}()
i = 11
}
複製程式碼