A 「defer」 statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.
Go官方文檔中對defer的執行時機做了闡述,分別是。
包裹defer的函數返回時
包裹defer的函數執行到末尾時
所在的goroutine發生panic時
defer執行順序當一個方法中有多個defer時, defer會將要延遲執行的方法「壓棧」,當defer被觸發時,將所有「壓棧」的方法「出棧」並執行。所以defer的執行順序是LIFO的。
執行順序如下
# 常規執行語句1 -> 語句2 -> 語句3 -> 語句4# 在語句2,語句3中添加defer後執行順序如下語句1 -> 語句4 -> 語句3(帶defer) -> 語句2(帶defer)
defer示例package mainimport "fmt"func main() {
d()
}func d() {
fmt.Print("start" + " ")
fmt.Print("processing1" + " ")
fmt.Print("processing2" + " ")
fmt.Print("end" + " ")
}
沒有defer:
start -> processing1 -> processing2 -> end
processing1、processing2 加入defer:
start -> end -> processing2 -> processing1
defer使用規則defer會實時解析參數package mainimport "fmt"func main() {
i := 0
defer fmt.Println(i)
i ++ return}// 0
這是因為雖然我們在defer後面定義的是一個帶變量的函數: fmt.Println(i). 但這個變量(i)在defer被聲明的時候,就已經確定其確定的值了
defer的類棧執行棧:先入後出
package mainimport "fmt"func f1() {
fmt.Println(1)
}func f2() {
fmt.Println(2)
}func main() { defer f1()
f2()
}// 2\1
func c() (i int) { defer func() { i++ }() return 1}func main() {
fmt.Println(c())
}// 2
在開頭的時候,我們說過defer是在return調用之後才執行的。這裡需要明確的是defer代碼塊的作用域仍然在函數之內,結合上面的函數也就是說,defer的作用域仍然在c函數之內。因此defer仍然可以讀取c函數內的變量(如果無法讀取函數內變量,那又如何進行變量清除呢…)。
當執行return 1 之後,i的值就是1. 此時此刻,defer代碼塊開始執行,對i進行自增操作。因此輸出2.
窮、優秀、攢錢