Go語言defer與return執(zhí)行的先后順序詳解
先了解什么是defer
Go語言中的defer與return執(zhí)行的先后順序
Go語言的 defer 語句會將其后面跟隨的語句進行延遲處理,在 defer 歸屬的函數即將返回時,將延遲處理的語句按 defer 的逆序進行執(zhí)行.也就是說,先被 defer 的語句最后被執(zhí)行,最后被 defer 的語句,最先被執(zhí)行。(與棧的先入后出是一個道理,也可以將其理解為入棧和出棧)
舉一個簡單的例子
func main() {
a, b := 111, 333
defer fmt.Println("b= ", b)
fmt.Println("a= ", a)
}
打印結果:
a= 111
b= 333
可以看到雖然執(zhí)行語句時b在前,但是輸出結果為b在最后被輸出。
defer 的用法
(簡單講解,細節(jié)請自行查閱資料)
一般用來釋放資源或者讀寫操作,當處理業(yè)務或邏輯中涉及成對的操作是一件比較煩瑣的事情,比如打開和關閉文件、接收請求和回復請求、加鎖和解鎖等。在這些操作中,最容易忽略的就是在每個函數退出處正確地釋放和關閉資源。比如下面一個例子
func main(){
a := 1
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
fmt.Fprintln(out, a)
}
輸出結果:
1
就可以在最后將結果打印到控制臺中去,類似的用法如關閉數據庫資源等等。如果這個例子太過于簡單,那么來看下個例子。
var a bool = true
defer func() {
fmt.Println("1")
}()
if a == true {
fmt.Println("2")
return
}
defer func() {
fmt.Println("3")
}()
輸出結果:
2
1
我們會發(fā)現defer語句也是需要被執(zhí)行的,如果在defer函數執(zhí)行之前就執(zhí)行return。defer后的語句就不會再被執(zhí)行了。但是如果是在return之前defer已經執(zhí)行,則defer中的語句將會在return執(zhí)行之前先一步進行執(zhí)行.
那么defer 和 return有什么聯(lián)系?
defer 是延遲執(zhí)行語句,return是返回語句,那么肯定出現誰先誰后的問題。下面看一個經典的例子吧
func increaseA() int {
var i int
defer func() {
i++
}()
return i
}
func increaseB() (r int) {
defer func() {
r++
}()
return r
}
func main() {
fmt.Println(increaseA())
fmt.Println(increaseB())
}
輸出結果為:
0
1
肯定有人覺得有疑惑,為什么A函數沒有輸出,B函數卻輸出了呢?為什么答案不是1和0呢?
原因:
先說結論:defer 修飾的匿名函數,只能更新具名返回值.那么這會導致什么問題呢?我們來逐步分析這個例子。
- 在increaseA()函數中有一個聲明i,表示i在該函數內已經被生成,是有名稱的變量。但該函數返回參數為匿名參數.
- 在increaseB()函數中沒有聲明r,是匿名變量。但該函數返回參數為具名參數.
- func increaseA() int,返回值i=0的時候該值已經被綁定到返回值里了,defer再去改i已經沒用了.
- func increaseB() (r int), 返回值r先把返回變量設為0,defer又把r改為1.這時候還能生效. 因此答案很明顯為 1 和 0.
更進一步理解
我們若想要進一步理解也可以去輸出匯編語句,然后進行研讀,可惜我是個菜鳥讀不懂匯編語言!但我們可以從return入手
我們要理解return 返回值的運行機制:
return并非原子操作,分為賦值,和返回值兩步操作.實際上return 執(zhí)行了兩步操作,因為返回值沒有命名,所以return默認指定了一個返回值(假設為a),首先將i賦值給a,后續(xù)的操作因為是針對i進行的,所以不會影響a, 此后因為a不會更新,所以return a不會改變.
var i int a := i return a
但是如果return的參數a是具名參數,就像上述例子中increaseB()函數一樣。a就相當于命名的變量i, 因為所有的操作都是基于命名變量i(a),返回值也是i, 所以每一次defer操作,都會更新返回值i.
省流小結
return會將返回值先保存起來,對于無名返回值來說,保存在一個臨時對象中,defer是看不到這個臨時對象的;而對于有名返回值來說,就保存在已命名的變量中。
以上就是Go語言defer與return執(zhí)行的先后順序詳解的詳細內容,更多關于Go defer return執(zhí)行順序的資料請關注腳本之家其它相關文章!
相關文章
Golang Gorm實現自定義多態(tài)模型關聯(lián)查詢
GORM 是一個流行的開源 ORM (Object-Relational Mapping) 庫,專為 Go 語言設計,它簡化了與 SQL 數據庫的交互,GORM 封裝了數據庫操作,使得開發(fā)者能夠通過簡單的鏈式調用來執(zhí)行 CRUD,本文給大家介紹了Golang Gorm實現自定義多態(tài)模型關聯(lián)查詢,需要的朋友可以參考下2024-11-11

