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