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