defer 匿名函式特性
-
執行方式類似其它語言中的解構函式,在函式體執行結束後按照呼叫順序的
相反順序
逐個執行//執行順序相反 package main import "fmt" func main() { fmt.Println("a") defer fmt.Println("b") defer fmt.Println("c") } /*輸出 a c b */
- 即使函式發生
嚴重的錯誤
也會執行,類似於try…except -
常用於 資源清理,檔案關閉,解鎖以及記錄時間等操作
- 支援匿名函式的呼叫
-
通過於匿名函式配合可在return之後修改函式計算的結果
-如果函式體內某個變數作為defer時匿名函式的引數,則在定義defer時即已經獲得了拷貝,否則 則時引用某個變數的地址//支援匿名函式 package main import "fmt" func main() { for i := 0; i < 3; i++ { defer func() { //函式體內的變數傳遞到defer匿名函式 fmt.Println(i) //此時引用的時變數i的地址 }() } } /*輸出 3 3 3 */
- Go沒有異常機制,但有panic/recover模式來處理錯誤
-
Panic可以在任何地方引發
panic錯誤機制
//panic 錯誤機制,遇到panic語句後,後面不會再執行 package main import "fmt" func main() { A() B() C() } func A() { fmt.Println("func a") } func B() { panic("Panic B") } func C() { fmt.Println("func") } /*輸出 A()--> func a B()---> panic: Panic B --------------- goroutine 1 [running]: main.B() C() C:/Users/faily/Desktop/workspace/src/defer1.go:17 +0x40 main.main() C:/Users/faily/Desktop/workspace/src/defer1.go:8 +0x2c exit status 2 exit status 1 */
-
defer,配合recover及匿名函式處理程式出現的嚴重錯誤(panic語句),調過程式錯誤,繼續執行,類似於python語言中
try...except
,finally
語句.//defer,recover機制,處理panic引發的機制 package main import "fmt" func main() { A() B() C() } func A() { fmt.Println("func a") } func B() { defer func() { //defer函式放在panic之前 if err := recover(); err != nil { //註冊recover函式(判斷是否觸發panic錯誤),並判斷 fmt.Println("Recover in B") //如果程式出現panic,並且err不為nil(真實存在) } }() //記住,defer的匿名函式大括號後要加上() panic("Panic B") //跳過程式錯誤,繼續後面的執行。 } func C() { fmt.Println("func C") } /*輸出 A()--> func a B()--> Recover in B C()--> func C */
– defer,匿名函式,變數傳遞,陣列array,for迴圈綜合
執行以下程式碼,並分析輸出結果
package main import "fmt" func main() { var fs = [4]func(){} //定義一個變數fs,型別為一個陣列,陣列元素的型別是匿名函式func for i := 0; i < 4; i++ { defer fmt.Println("defer i=", i) //defer,遵循的是先進後出,所以for迴圈,最後執行這一句,i作為變數,正常傳遞 defer func() { fmt.Println("defer closure i=", i) }() // i從外部傳遞進defer匿名函式中,作為變數而非匿名函式引數,此時引用的是i的記憶體地址(只會引用i的最後值) fs[i] = func() { fmt.Println("closure i=", i) } //為fs陣列索引賦值,i傳遞進匿名函式並沒有作為引數,所以i引用的是i的記憶體地址(只會引用i的最後值) fmt.Println(i) } for n, f := range fs { // for 迴圈陣列,執行每一個元素(匿名函式) fmt.Println(n) f() } } /*輸出 n=0 closure i= 4 n=1 closure i= 4 n=2 closure i= 4 n=3 closure i= 4 ------------------------ defer closure i= 4 defer i= 3 defer closure i= 4 defer i= 2 defer closure i= 4 defer i= 1 defer closure i= 4 defer i= 0 */
分析結果,詳見程式碼註釋