Go語言的延遲語句defer有哪些特點?通常在什么情況下使用?
Go語言的延遲語句(defer statement)具有以下特點:
通常情況下,延遲語句在以下情況下使用:
延遲語句的使用可以提高代碼的可讀性和可維護性,同時確保資源的釋放和清理操作按照逆序進行。它是Go語言中一種常用的編程技巧,用于處理資源管理和錯誤處理等場景。
實際開發中defer的使用并不像前面介紹的這么簡單,defer用不好,會陷入泥潭。
下面我從兩個角度帶大家避坑:
避免陷入泥潭的關鍵是必須深刻理解下面這條語句:
return xxx
上面這條語句經過編譯之后,實際上生成了三條指令:
1)返回值 =xxx。
2)調用 defer 函數。
3)空的 return。
第1和第 3 步是return語句生成的指令,也就是說return并不是一條原子指令;
第2步是 defer 定義的語句,這里可能會操作返回值,從而影響最終結果。
下面來看兩個例子,試著將return 語句和 defer語句拆解到正確的順序。
func f()(r int){ t:=5 defer func(){ t=t+5 }() return t}
拆解后:
func f()(r int){ t:=5 //1,賦值指令 r=t // 2.defer 被插入到賦值與返回之間執行,這個例子中返回值r沒被修改過 func(){ t=t+5 }() //3.空的 return 指令 return }
這里第二步實際上并沒有操作返回值r,因此,main函數中調用f()得到5。
圖片
func f()(r int){ defer func(r int){ r=r+5 }(r) return 1}
拆解后:
func f() (r int) { //1.賦值 r=1 //2.這里改的r是之前傳進去的r,不會改變要返回的那個r值 func(r int) { r=r+5 }(r) // 3. 空的 return return}
第二步,改變的是傳值進去的r,是形參的一個復制值,不會影響實參r。因此,main函數中需要調用f()得到1。
圖片
在使用匿名函數和非匿名函數作為defer的參數時,主要區別在于對函數參數的傳遞和作用域的影響:
產生這種區別的原因是,匿名函數和非匿名函數在定義和作用域上的差異。匿名函數可以直接在defer語句中定義,可以訪問外部函數的變量,而非匿名函數需要先定義好,然后作為參數傳遞。這種設計靈活性使得開發者可以根據具體的需求選擇合適的方式來使用defer語句。
當使用匿名函數作為defer的參數時,可以在defer語句中直接定義匿名函數,并訪問外部變量。
以下是一個示例代碼:
package mainimport "fmt"func main() { x := 10 defer func() { fmt.Println("Deferred anonymous function:", x) }() x = 20 fmt.Println("Before return:", x)}
在上述示例中,匿名函數作為defer的參數,可以訪問外部變量x。在函數返回之前,defer語句中的匿名函數會執行,并打印出x的值。
輸出結果如下:
圖片
當使用非匿名函數作為defer的參數時,需要先定義好函數,然后將函數名作為defer的參數傳遞。
以下是一個示例代碼:
package mainimport "fmt"func main() { x := 10 defer printX(x) x = 20 fmt.Println("Before return:", x)}func printX(x int) { fmt.Println("Deferred function:", x)}
在上述示例中,printX函數作為defer的參數傳遞,函數定義在main函數之后。
在函數返回之前,defer語句中的printX函數會執行,并打印出傳遞的參數x的值。輸出結果如下:
圖片
通過以上示例,我們可以明確體現出使用匿名函數和非匿名函數作為defer的參數的區別。
匿名函數可以直接在defer語句中定義,并訪問外部變量,而非匿名函數需要先定義好函數,然后將函數名作為參數傳遞。
通過前面帶著大家拆解了defer的語句的執行,相信大家可以更好的理解了。
本文轉載自微信公眾號「 程序員升級打怪之旅」,作者「 王中陽Go」,可以通過以下二維碼關注。
轉載本文請聯系「 程序員升級打怪之旅」公眾號。
本文鏈接:http://www.www897cc.com/showinfo-26-30059-0.html解密defer語句:避免踩坑,掌握延遲執行的正確姿勢
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Angular怎么還沒死