Go語言的 defer 語句會把它後面的語句記錄下來,多個defer的語句記錄時像一個壓棧的操作,
在 defer 歸屬的函數即將返回時,將記錄的語句按 defer 的逆序進行執行,
也就是說,最後被 defer 的語句,最先被執行,類似出棧。
在業務處理中,打開和關閉文件、接收請求和回覆請求、加鎖和解鎖等操作,
defer 語句正好是在函數退出時執行的語句,所以使用 defer 能非常方便地處理資源釋放問題。
可以利用defer語句的特性,防止資源沒有被釋放。
看到一個面試題,就是不好好用defer 語句,非要花裏胡哨的......但是對於理解defer 執行順序挺有用。
package main
import "fmt"
// defer 在函數中的流程是:
// 1, 記錄defer語句(不執行)
// 2, return 語句給返回值賦值
// 3, 執行 defer語句
// 4, 底層RET指令
func f1() int {
x := 5
defer func() {
x++
}() // 立即執行函數
return x
} // 1, 返回值沒有指定變量, return x 賦值爲 5,可以理解爲開闢了一個沒有命名的內存把x的值給了它,存的值是 5
// 2, defer中x++ 修改的是x, 不是返回值,
// 3, 執行RET 真正返回的是 5
func f2() (x int) {
defer func() {
x++
}()
return 5
} // 1, 返回值爲 x 已確定, return 5 == x
// 2, defer 執行 x++,修改了x的值,
// 3, RET x, 此時 x == 6
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
} // 1, 返回值爲 y 已確定,return 的 x = y = 5
// 2, defer 執行 x++, 修改的是x, 不是返回值 (x 的值賦給 y, 然後再去修改 x, 跟 y 是沒有關係的)
// 3, 真正RET = y = 5
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5
} // 1, 返回值爲 x 已確定,return 的 5 = x,
// 2, defer 函數x作爲參數,執行 x++, defer匿名函數中的x 和返回值不是一個x,只是x的值作爲參數去defer的函數中溜達了一圈,是x的值,不是x
// 3, 真正RET的一個變量值爲 5
func f5() (x int) {
defer func(x int) int {
x++
return x
}(x)
return 5
} // 1, 返回值爲 x 已確定,return 的 5 = x,
// 2, defer 函數x作爲參數返回值爲int型, 執行 x++, defer匿名函數中的x 和返回值同樣不是一個x,而且這個defer的匿名函數的返回值並沒有被接收
// 3,所以真正返回的值還是 5
func f6() (x int) {
defer func(x *int) {
(*x)++
}(&x)
return 5
} // 1, return 5, 此時 x = 5,
// 2, defer語句執行,傳入的是x的地址,在內存地址中修改了返回值x, x==6
// 3, 函數int型返回值 訪問 x 時, x 的地址存的是 6,所以 真正 RET 爲 6
func main() {
fmt.Println(f1()) // 5
fmt.Println(f2()) // 6
fmt.Println(f3()) // 5
fmt.Println(f4()) // 5
fmt.Println(f5()) // 5
fmt.Println(f6()) // 6
}