defer關鍵字
defer
是Golang中一個非常重要的關鍵字,主要是用於註冊延遲調用,這些調用在return
時纔會執行,通常用來銷燬資源
示例
簡單場景
最簡單的使用場景
import "fmt"
type handler struct {
}
func (h *handler) close() {
fmt.Println("close handler")
}
func (h *handler) call() {
fmt.Println("call function exec")
}
func main() {
h := new(handler)
defer h.close()
h.call()
}
call function exec
close handler
defer
註冊的函數是在return
返回時纔會被調用,主要用於關閉一些資源句柄之類的
多次註冊
註冊多個調用的場景
package main
import "fmt"
type handler struct {
}
func (h *handler) close1() {
fmt.Println("close1 handler")
}
func (h *handler) close2() {
fmt.Println("close2 handler")
}
func (h *handler) call() {
fmt.Println("call function exec")
}
func main() {
h := new(handler)
defer h.close1()
defer h.close2()
h.call()
}
call function exec
close2 handler
close1 handler
defer
允許註冊多個調用,按先進後出的順序執行
變量修改
在註冊後修改了變量所指向的值的情況
package main
import "fmt"
type handler struct {
i int
}
func (h *handler) close() {
fmt.Println(h.i, "close handler")
}
func main() {
h := &handler{i: 1}
defer h.close()
h = &handler{i: 2}
}
1 close handler
defer
所註冊的函數參數會被複制一份保存起來,並不受後續的修改所影響
不過要注意的是這裏只是複製了go
的指針,指針指向的地址不會變,但是指針指向的地址上的內容是可以修改變動的
閉包
與上面一種場景相似的就是閉包的場景
package main
import "fmt"
type handler struct {
i int
}
func (h *handler) close() {
fmt.Println(h.i, "close handler")
}
func main() {
h := &handler{i: 1}
defer func() {h.close()}()
h = &handler{i: 2}
}
2 close handler
類似於上面的指針,閉包不會發生改變,但是閉包所引用的值h
可以發生改變
異常情況
在調用os.Exit
、log.Fatal
這些函數直接退出程序時,defer
註冊的函數不會被執行