Go語言defer分析
什么是defer?
defer語句是專門在函數(shù)結(jié)束以后做一些清理工作的。我們先舉一個例子來更好的理解,現(xiàn)在有一個函數(shù),它的作用是把一個文件內(nèi)容拷貝到另一個文件。
func CopyFile(dstName string, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
written, err = io.Copy(dst, src)
src.Close()
dst.Close()
return
}
以上代碼是可以正常執(zhí)行的,但是存在一個問題,如果os.Create執(zhí)行失敗,那么就無法執(zhí)行到文件資源的Close函數(shù)。進程每打開一個文件就會占用一個文件描述符,而在系統(tǒng)當(dāng)中,文件描述符是有上限的,可以通過ulimit -n查看,如果資源沒有被及時釋放,會出現(xiàn)資源浪費的情況。如果打開文件過多,也會出現(xiàn)Too many open files的提示。這個時候就需要通過defer來解決問題了,代碼如下。
func CopyFile(dstName string, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
written, err = io.Copy(dst, src)
return
}
defer語句會在return參數(shù)設(shè)置之后、函數(shù)返回給調(diào)用者之前執(zhí)行,這樣就不再擔(dān)心文件資源無法被Close了。
defer的三個規(guī)則
規(guī)則一:被deferred的函數(shù)參數(shù)在defer時確定
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
我們通過以上代碼來理解這個拗口的規(guī)則,如果根據(jù)官方的定義來理解這段代碼,變量i的值鐵定為1,但實際執(zhí)行的結(jié)果不是1,卻是0。
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.
那我們再重新來理解這個規(guī)則,變量i是在逐行執(zhí)行到defer語句的時候就已經(jīng)確定了值,這個時候變量i還沒有進行自增,所以輸出的結(jié)果應(yīng)該是0而不是1。
規(guī)則二:被deferred函數(shù)執(zhí)行順序遵循LIFO原則
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
LIFO全稱為Last In First Out,意為后進先出,棧是一種典型的LIFO數(shù)據(jù)結(jié)構(gòu)。defer也是如此,拿以上代碼為例,先后遍歷了四次,也就是做了四次壓棧操作。同理,在函數(shù)return之前,就會逐一出棧,倒序執(zhí)行defer語句,所以上述代碼輸出內(nèi)容為3210。

規(guī)則三:deferred函數(shù)可以讀取和修改函數(shù)的返回值
func c() (i int) {
defer func() { i++ }()
return 1
}
我們定義一個defer函數(shù),將變量i自增,那么最終變量i的值為2。我們從官方文檔中可以看出,defer語句是在函數(shù)設(shè)置返回值后,且在返回給主調(diào)函數(shù)前執(zhí)行的,根據(jù)這個思路,c函數(shù)已經(jīng)return了1,這個時候執(zhí)行了defer函數(shù),將返回的結(jié)果1進行了自增,然后返回給主調(diào)函數(shù),這個時候主調(diào)函數(shù)拿到的值就是2了。
deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller

浙公網(wǎng)安備 33010602011771號