golang中defer语句使用小结
defer是Go語言中的延遲執行語句,用來添加函數結束時執行的代碼,常用于釋放某些已分配的資源、關閉數據庫連接、斷開socket連接、解鎖一個加鎖的資源。Go語言機制擔保一定會執行defer語句中的代碼。其它語言中也有類似的機制,比如Java、C#語言里的finally語句,C++語言里的析構函數(Destructor)可以起類似的作用,C++語言機制擔保在對象被銷毀前一定會執行析構函數中的代碼。C++中的析構函數析構的是對象,Go中的defer析構的是函數。
一、defer語句執行時機
defer語句在函數返回之前 或者 函數中 return語句(return語句可能調用另一個函數) 之后執行。示例代碼:
package mainimport ("fmt" )func main() {fmt.Println(deferReturn()) }func deferReturn() (ret int) {defer func() {ret++}()return 10 }上述代碼打印出來的值是:11。?defer語句 匿名函數中的“ret++” 對返回值 10 加 1 變成了 11。再來看一個defer語句出現在return語句之后的代碼:
func returnDefer() (ret int) {return 0defer func() {ret++ret++}()return 1 }上述returnDefer函數的返回值是:0。原因是defer語句還沒有添加上代碼執行到"return 0"函數就返回了,因此defer語句就沒有執行。
二、多個defer語句的執行順序是逆序執行
當出現多條 defer 語句時以逆序執行(類似棧,即后進先出)。示例代碼:
func deferSample() {for i := 0; i < 5; i++ {defer fmt.Printf("%d ", i)} }上述代碼將會輸出:4 3 2 1 0
三、defer與panic
1、在panic語句后面的defer語句不被執行
示例代碼:
func panicDefer() {panic("panic")defer fmt.Println("defer after panic") }上述代碼的輸出如下:
panic: panic
goroutine 1 [running]:
main.panicDefer()
??? E:/godemo/testdefer.go:17 +0x39
main.main()
??? E:/godemo/testdefer.go:13 +0x20
Process finished with exit code 2
可以看到 defer 語句沒有執行。
2、在panic語句前的defer語句會被執行
示例代碼:
func deferPanic() {defer fmt.Println("defer before panic")panic("panic") }上述代碼的輸出如下:
defer before panic
panic: panic
goroutine 1 [running]:
main.deferPanic()
??? E:/godemo/testdefer.go:19 +0x95
main.main()
??? E:/godemo/testdefer.go:14 +0x20
Process finished with exit code 2
defer 語句輸出了內容。
Go中的panic類似其它語言中的拋出異常,panic后面的代碼不再執行(panic語句前面的defer語句會被執行)。
四、return 的實現邏輯
1、第一步給返回值賦值(若是有名返回值直接賦值,匿名返回值 則 先聲明再 賦值) ;
2、第二步調用RET返回指令并傳入返回值,RET會檢查是否存在defer語句,若存 在就先逆序插播 defer語句 ;
3、最后 RET 攜帶返回值退出函數 。
可以看出 , return 不是一個原子操作,函數返回值與 RET 返回值并不一定一致。
五、defer、 return、返回值三者順序
defer、 return、返回值 三者的執行順序是 : return 最先給返回值賦值;接著 defer 開始執行一些收尾工作;最后 RET 指令攜帶返回值退出函數。
總結
以上是生活随笔為你收集整理的golang中defer语句使用小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# string转double,dou
- 下一篇: Redis Flushall 命令