golang 詳解defer
阿新 • • 發佈:2018-03-13
什麽是 strong final 例子 拋出異常 包含 over def span
什麽是defer
defer用來聲明一個延遲函數,把這個函數放入到一個棧上, 當外部的包含方法return之前,返回參數到調用方法之前調用,也可以說是運行到最外層方法體的"}"時調用。我們經常用他來做一些資源的釋放,比如關閉io操作func doSomething(fileName string) { file,err := os.Open(fileName) if err != nil { panic(err) } defer file.Close() }
defer 可以保證方法可以在外圍函數返回之前調用。有點像其他言的 try finally
try{ }finally{ }
defer 讀寫外部變量
defer聲明的函數讀寫外部變量,和閉包差不多。比如下面的代碼
func doSomething() { v := 10 defer func() { fmt.Println(v) v++ fmt.Println(v) }() v += 5 }
輸出為
15 16
就像閉包一樣,如果不是defer函數方法內的變量會向上一層函數訪問變量,重新做計算。
defer 讀寫命名的返回值
這個例子中,defer聲明的方法,給命名的返回值自增11func doSomething() (rev int) { 2 defer func() { 3 rev++ 4 }() 5 6 return 5 7 }
第6行的return 相當於
return rev = 5
defer 聲明的匿名函數會在return 之前執行,相當於
rev = 5 // 執行defer方法 rev++ //然後return return
所以結果是6
我把代碼做一點點修改
1 func doSomething() (rev int) { 2 v := 103 defer func() { 4 v++ 5 }() 6 7 return v 8 }
第7行返回的是局部變量v.
return v 相當於 return rev = v
defer 函數裏是對局部變量v的操作,所以與返回的rev沒有關系。所有執行的結果是:10
defer 執行順序
當有多個defer時執行順序逆向的,後進先出:func doSomething() { defer fmt.Println(1) defer fmt.Println(2) }
會先輸出2,再輸出1
defer 處理異常
panic拋出異常後,如果不處理應用程序會崩潰。為了防止程序崩潰,我們可以在defer的函數裏使用recover來捕獲中異常:func doSomething() { defer func() { if err := recover(); err != nil { fmt.Print(err) } }() fmt.Println("Running...") panic("run error") }
輸出:
Running...
run error
recover 會捕獲panic的異常。我再把代碼做一點點修改:
func doSomething() { defer func() { if err := recover(); err != nil { fmt.Print(err) } }() defer func() { panic("defer error") }() fmt.Println("Running...") panic("run error") }
輸出結果
Running...
defer error
因為 recover()只捕獲最後一次panic
golang 詳解defer