多個延遲執行語句的處理順序函數
package main import ( "fmt" ) func main() { fmt.Println("defer begin") // 將defer放入延遲調用棧 defer fmt.Println(1) defer fmt.Println(2) // 最後一個放入, 位於棧頂, 最早調用 defer fmt.Println(3) fmt.Println("defer end") }
結果分析以下:spa
處理業務或邏輯中涉及成對的操做是一件比較煩瑣的事情,好比打開和關閉文件、接收請求和回覆請求、加鎖和解鎖等。在這些操做中,最容易忽略的就是在每一個函數退出處正確地釋放和關閉資源。
defer 語句正好是在函數退出時執行的語句,因此使用 defer 能很是方便地處理資源釋放問題。code
package main func main() { panic("crash") }
當 panic() 觸發的宕機發生時,panic() 後面的代碼將不會被運行,可是在 panic() 函數前面已經運行過的 defer 語句依然會在宕機發生時發生做用,參考下面代碼blog
package main import "fmt" func main() { defer fmt.Println("宕機後要作的事情1") defer fmt.Println("宕機後要作的事情2") panic("宕機") }
輸出結果爲:資源
宕機後要作的事情2 宕機後要作的事情1 panic: 宕機 goroutine 1 [running]: main.main() F:/src/tester/main.go:8 +0x1a4
不管是代碼運行錯誤由 Runtime 層拋出的 panic 崩潰,仍是主動觸發的 panic 崩潰,均可以配合 defer 和 recover 實現錯誤捕捉和恢復,讓代碼在發生崩潰後容許繼續運行。class
defer func() { if r:= recover();r != nil{ log.Printf("Runtime error caught :%v",r) } }() foo()