預習內容
- defer 的作用有哪些?
- 多個 defer 的執行順序是怎樣的?
- defer,return,函式回傳值 三者之間的執行順序
defer的作用
go中的defer是延遲函式,一般是用于釋放資源或者收尾作業,
由于defer是具有延遲特性且執行動作是在函式return之后,因此作為資源釋放作用再好不過,
- 典型例子:釋放鎖、關閉檔案、關閉鏈接等
// 釋放鎖
func getValue() {
s.Lock()
defer s.Unlock()
...
}
// 關閉檔案
func read() {
f, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
defer f.Close()
...
}
// 關閉鏈接
func connect() {
resp, err := grequests.Get(s.cfg.GateApiCrossMarginUrl, nil)
defer resp.Close()
...
}
// 收尾作業,defer 同時也是函式,可以做很多收尾相關作業
func closeConnection() {
...
defer func() {
file.close()
close(readChan)
}
...
}
- 還有作用就是捕獲 panic,這個功能在defer里也是典型用法
func sendChan() {
// 此處捕獲 panic 進行 recover 防止程式崩潰
defer func() {
if ok := recover(); ok != nil {
fmt.Println("recover")
}
}()
// 向已經關閉的chan發送資料,此處會引起 panic
dataChan <- "message"
...
}
defer 釋放資源『避坑指南』
資源釋放動作一定緊跟資源使用(打開、連接)陳述句,不然defer可能不會被執行到,導致記憶體泄露
// 關閉檔案
func read() error {
f1, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
if err != nil {
return err
}
// 此時,defer還沒執行到,提前return了,無效defer導致記憶體泄露
defer f1.Close()
// 正確用法,緊跟資源使用陳述句
f2, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
defer f2.Close()
if err != nil {
return err
}
}
defer 的呼叫順序
墻裂建議不要先看后面的介紹做下面的題目,此處先跳過介紹defer呼叫順序,看看下面比較典型的對defer順序判斷,你能看出來幾個?
func deferFunc1(i int) (t int) {
t = i
defer func() {
t += 1
}()
return t
}
func deferFunc2(i int) int {
t := i
defer func() {
t += 1
}()
return t
}
func deferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 1
}
func deferFunc4() (t int) {
defer func(i int) {
fmt.Println(i)
fmt.Println(t)
}(t)
t = 0
return 1
}
func ExecDeferFunc() {
// 猜猜下面輸出的內容和順序
fmt.Println(deferFunc1(1))
fmt.Println(deferFunc2(1))
fmt.Println(deferFunc3(1))
deferFunc4()
}
猜想結果可能是:2,2,1,0,0 或者 2,2,1,1,1 ?
估計比較模糊的地方應該是函式回傳值 和 return value(函式回傳值)關系不明確,還有就是對defer產生作用的時機不明確
正文開始!
再次強調defer是延遲函式,執行動作在return之后,defer相當于是將執行動作壓入堆疊中,越是后面的defer越是先執行,執行順序是LIFO(后進先出),
特別指出:有函式回傳值的則return將結果寫入回傳值,defer進行收尾,可以看做 return最先執行,然后return將結果存入回傳值,最后defer執行
那么基于剛剛的介紹再回頭去看得到的『實際結果是:2,1,2,0,1』
復習內容
- defer 用于資源釋放和收尾作業
- 多個 defer 呼叫順序是 LIFO(后入先出),defer后的操作可以理解為壓入堆疊中
- defer,return,return value(函式回傳值) 執行順序:首先return,其次return value,最后defer,defer可以修改函式最侄訓傳值,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295958.html
標籤:Go
下一篇:從Python到Go:初學筆記
