defer是個Go語言中的一個關鍵詞。從語法上來講,defer語句是defer關鍵詞後面跟着一個函數/方法調用。函數和參數表達式在defer語句所在的位置就已經被檢驗了。但是實際上的函數/方法調用的話,一直推遲到所在函數的返回結束或者出錯結束。任何調用都可以被推遲。多個被推遲的函數調用,實際調用順序正好與它們代碼調用位置相反。
func print(a int) {
fmt.Println(a)
}
func Add(a, b int) int {
defer print(a)
a = a + b
return a
}
fmt.Println(Add(4, 3))
上面這段代碼,defer語句輸出的是4,Add返回的值是7。
defer可以用於文件的打開和關閉,鎖的打開和關閉。
package ioutil
func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.close()
return ReadAll()
}
上面的代碼在執行完return語句後,文件指針f被關閉。
var mu sync.Mutex
var m = make(map[string]int)
func lookup(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}
上面代碼先上鎖,進入臨界區,返回m裏key對應的值,然後退出臨界區,解除鎖。
如果函數的返回值有變量名,defer可以用於打印函數返回值。這在debug中有一定用處。
func double(x int) (result int) {
defer func() { fmt.Println("double(%d) = %d\n", x, result) }()
return x + x
}
_ = double(4)
上面的函數會輸出“double(4) = 8"。