Go語言-defer特性和使用場景
阿新 • • 發佈:2022-04-10
Go語言的defer主要用於延遲呼叫,會在當前函式返回之前執行defer註冊的函式。類似其他語言(例如java)中的try...catch...finally語句,利用這個特性可以用來釋放資源等操作,下面歸納總結一下defer的基本用法。
一、defer的特性
1、延遲呼叫
1 func main() { 2 3 fmt.Println("start...") 4 defer fmt.Println("defer...") 5 fmt.Println("end...") 6 }
執行結果如下:
start...
end...
defer...
可以看到,defer執行在函式退出之前,需要注意的是:defer必須放在函式內部。
2、LIFO(先進後出,棧特性)
func main() { for i:= 0; i < 5; i++ { defer fmt.Println(i) } }
執行結果如下:
4 3 2 1 0
通過執行結果可以看到,執行的結果和入棧的順序是相反的,即後進先出。
3、defer的作用域
func main() { func() { defer println("defer...") }() println("end...") }
執行結果如下:
defer...
end...
可以看到,defer的作用域只在函式內部,因為defer只能是在函式內部,所以不會對函式外執行順序產生影響。
4、異常場景
func main() { defer func() { e := recover(); if e != nil { println("defer...") } }() panic("throw panic") }
執行結果如下:
defer...
可以看到,在panic發生時也能執行,例如在資源洩漏、死鎖等場景下特別有用,因為發生panic時程式程序不一定會終止,可能被外層reciver住,這個時候可以利用defer來確保必要的執行。但是使用限制是:defer必須和recover結合使用才有意義。
二、defer的使用場景
1、併發同步控制
2、鎖場景,用來確保鎖釋放,在其他語言中一般通過try...catch...finally來確保最終執行,但是Go語言的defer能一更加優雅的程式碼格式來實現,便於程式的閱讀性,同時能防止程式設計師忘記釋放導致出現死鎖等問題,如下:
xx.Lock()
defer xx.unLock()
...相關業務程式碼
這樣的程式碼看起來是不是比在加鎖和釋放鎖之間插入大量的業務程式碼看起來更加便於理解和維護呢?
3、資源釋放,其實跟2的鎖場景類似,都是在資源開啟後,直接通過defer延遲呼叫的特性實現資源釋放
xx.open(資源)
defer xx.close(資源)
...相關業務程式碼