golang中defer的使用規則

2021-09-11 19:04:51 字數 2045 閱讀 3737

在golang當中,defer**塊會在函式呼叫鍊錶中增加乙個函式呼叫。這個函式呼叫不是普通的函式呼叫,而是會在函式中正常返回,也就是在return之後新增乙個函式呼叫。因此,defer通常用來釋放函式內部變數

為了更好的學習defer的行為,我們首先來看下面一段**:

func copyfile(dstname, srcname string) (written int64, err error) 

dst, err := os.create(dstname)

if err != nil

written, err = io.copy(dst, src)

dst.close()

src.close()

return

}

這段**可以執行,但存在』安全隱患』。如果呼叫dst, err := os.create(dstname)失敗,則函式會執行return退出執行。但之前建立的src(檔案控制代碼)沒有被釋放。 上面這段**很簡單,所以我們可以一眼看出存在檔案未被釋放的問題。 如果我們的邏輯複雜或者**呼叫過多時,這樣的錯誤未必會被及時發現。 而使用defer則可以避免這種情況的發生,下面是使用defer的**:

func copyfile(dstname, srcname string) (written int64, err error) 

defer src.close()

dst, err := os.create(dstname)

if err != nil

defer dst.close()

return io.copy(dst, src)

}

通過defer,我們可以在**中優雅的關閉/清理**中所使用的變數。defer作為golang清理變數的特性,有其獨有且明確的行為。以下是defer三條使用規則。

我們通過以下**來解釋這條規則:

func a()
上面我們說過,defer函式會在return之後被呼叫。那麼這段函式執行完之後,是不用應該輸出1呢?

讀者自行編譯看一下,結果輸出的是0。why?

這是因為雖然我們在defer後面定義的是乙個帶變數的函式: fmt.println(i). 但這個變數(i)在defer被宣告的時候,就已經確定其確定的值了。 換言之,上面的**等同於下面的**:

func a()
為了更為明確的說明這個問題,我們繼續定義乙個defer:

func a()
通過執行結果,可以看到defer輸出的值,就是定義時的值。而不是defer真正執行時的變數值(很重要,搞不清楚的話就會產生於預期不一致的結果)

但為什麼是先輸出1,在輸出0呢? 看下面的規則二。

**當同時定義多個defer**塊時,golang按照先定義後執行,先進後出的順序依次呼叫defer。**不要問為什麼,golang就是這麼定義的。我們用下面的**加深記憶和理解:

func b() 

}

在迴圈中,依次定義了四個defer**塊。結合規則一,我們可以明確得知每個defer**塊應該輸出什麼值。 按照先進後出的原則,我們可以看到依次輸出了3210.

先看下面的**:

func c() (i int) ()

return 1

}

輸出結果是12. 在開頭的時候,我們說過***defer是在return呼叫之後才執行的***。 這裡需要明確的是defer**塊的作用域仍然在函式之內,結合上面的函式也就是說,defer的作用域仍然在c函式之內。因此defer仍然可以讀取c函式內的變數(如果無法讀取函式內變數,那又如何進行變數清除呢…)。

當執行return 1 之後,i的值就是1。此時此刻,defer**塊開始執行,對i進行自增操作。 因此輸出2。

掌握了defer以上三條使用規則,那麼當我們遇到defer**塊時,就可以明確得知defer的預期結果。

**個人部落格:

Golang中的defer使用

在golang當中,defer 塊會在函式呼叫鍊錶中增加乙個函式呼叫。這個函式呼叫不是普通的函式呼叫,而是會在函式正常返回,也就是return之後新增乙個函式呼叫。因此,defer通常用來釋放函式內部變數。為了更好的學習defer的行為,我們首先來看下面一段 func copyfile dstnam...

golang中defer使用小結

golang語言中defer的使用場景較多,用於鎖的關閉,連線的延遲關閉等,通常在函式的結束時呼叫,詳細的講就是在函式結束時返回值賦值後,返回前執行defer的方法,最後才返回,另外defer確實有一定的開銷,拒絕濫用。第一點 defer 不帶函式執行,defer可以理解像棧,先進後出,看下面 fu...

golang中defer函式的使用

defer是什麼?在go語言中,可以使用關鍵字defer向函式註冊退出呼叫,即主函式退出時,defer後的函式才被呼叫。defer語句的作用是不管程式是否出現異常,均在函式退出時自動執行相關 defer的用途 在函式中,程式設計師經常需要建立資源 比如 資料庫連線 檔案控制代碼 鎖等 為了在函式執行...