关键字之defer、panic、recover
一、defer? ?? ?
?????????1、?defer延遲調用,完成一些收尾工作。無論函數或方法是否出錯,一定會在退出當前函數或者方法之前調用傳入的函數(只對函數或方法生效,代碼塊不生效),常被用于關閉文件描述符、關閉數據庫連接以及解鎖資源。
? ? ? ? 2、defer的實現原理
????????編譯器會將?defer?關鍵字都轉換成?runtime.deferproc?函數,負責創建新的延遲調用;runtime.deferreturn?函數負責在函數調用結束時執行所有的延遲調用,runtime.deferreturn?函數會多次判斷當前 Goroutine 的?_defer?鏈表中是否有未執行的剩余結構,在所有的延遲函數調用都執行完成之后,該函數才會返回。
? ? ? ? 3、多次調用 defer 時的執行順序問題:
? ? ? ? 后調用的defer函數會先執行,先調用的defer函數會后執行。內部其實是一個defer鏈表,會綁定到當前的goroutine。
? ?defer?關鍵字插入時是從后向前的,而?defer?關鍵字執行是從前向后的,而這就是后調用的?defer?會優先執行的原因。
? ? ? ?4、 defer的傳值方式及預計算問題:
????????defer的傳值采用值傳遞,調用defer時會立刻對函數中引用的外部參數進行拷貝進行值傳遞,導致實際執行時。
????????解決此問題可以向 defer 關鍵字傳入匿名函數,雖然調用defer時也使用值傳遞,但是因為拷貝的是函數指針,所以 time.Since(startedAt) 會在 main 函數返回前被調用并打印出符合預期的結果。
二、panic和recover
panic,調用panic時會立刻停止執行函數的其他代碼,并觸發當前Goroutine的defer鏈表(defer要定義在panic之前,否則defer不生效);
recover,可以中止panic造成的程序崩潰,且只能定義在defer中。
觸發panic時,會先打印defer的函數再打印異常堆棧信息
package main import "fmt" func main() { defer func() { fmt.Println("a")}() defer func() { fmt.Println("b")}() defer func() { fmt.Println("c")}() panic("error") }打印: GOROOT=D:\Go #gosetup GOPATH=D:\goland\workspace #gosetup D:\Go\bin\go.exe build -o C:\Users\80310624\AppData\Local\Temp\___1go_build_main_go.exe D:\goland\workspace\src\proj_test01\main.go #gosetup C:\Users\80310624\AppData\Local\Temp\___1go_build_main_go.exe #gosetup c b a panic: errorgoroutine 1 [running]: main.main()D:/goland/workspace/src/proj_test01/main.go:15 +0x85Process finished with exit code 2總結
以上是生活随笔為你收集整理的关键字之defer、panic、recover的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手把手实现一条延时消息
- 下一篇: 不懂 ZooKeeper?没关系,这一篇