Go語言defer分析

什麼是defer?

defer語句是專門在函數結束之後作一些清理工做的。咱們先舉一個例子來更好的理解,如今有一個函數,它的做用是把一個文件內容拷貝到另外一個文件。golang

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
}

以上代碼是能夠正常執行的,可是存在一個問題,若是os.Create執行失敗,那麼就沒法執行到文件資源的Close函數。進程每打開一個文件就會佔用一個文件描述符,而在系統當中,文件描述符是有上限的,能夠經過ulimit -n查看,若是資源沒有被及時釋放,會出現資源浪費的狀況。若是打開文件過多,也會出現Too many open files的提示。這個時候就須要經過defer來解決問題了,代碼以下。c#

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參數設置以後、函數返回給調用者以前執行,這樣就再也不擔憂文件資源沒法被Close了。數據結構

defer的三個規則

規則一:被deferred的函數參數在defer時肯定

func a() {
	i := 0
	defer fmt.Println(i)
	i++
	return
}

咱們經過以上代碼來理解這個拗口的規則,若是根據官方的定義來理解這段代碼,變量i的值鐵定爲1,但實際執行的結果不是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.lua

那咱們再從新來理解這個規則,變量i是在逐行執行到defer語句的時候就已經肯定了值,這個時候變量i尚未進行自增,因此輸出的結果應該是0而不是1。code

規則二:被deferred函數執行順序遵循LIFO原則

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

LIFO全稱爲Last In First Out,意爲後進先出,棧是一種典型的LIFO數據結構。defer也是如此,拿以上代碼爲例,前後遍歷了四次,也就是作了四次壓棧操做。同理,在函數return以前,就會逐一出棧,倒序執行defer語句,因此上述代碼輸出內容爲3210blog

規則三:deferred函數能夠讀取和修改函數的返回值

func c() (i int) {
	defer func() { i++ }()
	return 1
}

咱們定義一個defer函數,將變量i自增,那麼最終變量i的值爲2。咱們從官方文檔中能夠看出,defer語句是在函數設置返回值後,且在返回給主調函數前執行的,根據這個思路,c函數已經return了1,這個時候執行了defer函數,將返回的結果1進行了自增,而後返回給主調函數,這個時候主調函數拿到的值就是2了。進程

deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller資源

相關文章
相關標籤/搜索