Golang全面深入系列之 defer

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

 

前言

    大家都知道go語言的defer功能很強大,對於資源管理非常方便,但是如果沒用好,也會有陷阱哦。Go 語言中延遲函數 defer 充當著 try...catch 的重任,使用起來也非常簡便,那麼defer、return、傳回值、panic 之間的執行順序是怎麼樣的呢,下面我們就一點一點來揭開它的神秘面紗!話不多說了,來一起看看介紹吧。

 

Defer介紹

defer語句用於函數在返回之前執行函數調用。這個定義可能看起來很複雜,但通過一個例子很容易理解。

package mainimport ("fmt")func finished() {fmt.Println("finished")}func largest() {defer finished()fmt.Println("largest()執行")}func main() {largest()}

也就是在func結束(return)之前執行的動作。無論定義在普通語句的前後。

defer同樣支援方法的調用。

package mainimport ("fmt")type person struct {firstName stringlastName string}func (p person) fullName() {fmt.Printf("%s %s",p.firstName,p.lastName)}func main() {p := person {firstName: "John",lastName: "Smith",}defer p.fullName()fmt.Printf("Welcome ")}

 

PS: defer聲明時會先計算確定參數的值,defer延遲執行的僅是其函數體

import (      "fmt")func printA(a int) {      fmt.Println("value of a in deferred function", a)}func main() {      a := 5    defer printA(a)    a = 10    fmt.Println("value of a before deferred function call", a)}

 當defer被聲明時, 其參數a值就會被即時解析,並不執行函數體內內容, 那麼後續的修改並不會影響當前參數值。

 

驗證結果:

package mainimport ("fmt""time")func main() {defer P(time.Now())time.Sleep(5*time.Second)fmt.Println("main ", time.Now())}func P(t time.Time) {fmt.Println("defer", t)fmt.Println("P ", time.Now())}

執行結果:

main  2018-03-16 14:43:25.10348 +0800 CST m=+5.003171200defer 2018-03-16 14:43:20.1033124 +0800 CST m=+0.003003600P  2018-03-16 14:43:25.142031 +0800 CST m=+5.041722200

 

defer後進先出

簡單的理解為先聲明的defer後執行(倒序執行defer語句)。

package mainimport (      "fmt")func main() {      name := "Naveen"    fmt.Printf("Orignal String: %s\n", string(name))    for _, v := range []rune(name) {        defer fmt.Printf("%c", v)    }}

輸出為: neevaN

 

defer / return / 傳回值 / panic之間的執行順序

現在我們分兩種情況分析它們的執行順序:

1. return前將傳回值賦值

2. 檢查是否有defer並執行

3. 最後return 攜帶傳回值退出函數

 

第一種: 匿名傳回值

package mainimport ("fmt")func main() {fmt.Println("a return:", a()) // 列印結果為 a return: 0}func a() int {var i intdefer func() {i++fmt.Println("a defer2:", i) // 列印結果為 a defer2: 2}()defer func() {i++fmt.Println("a defer1:", i) // 列印結果為 a defer1: 1}()return i}

輸出結果:

a defer1: 1a defer2: 2a return: 0

解釋: 匿名傳回值是在return之前被聲明( 鑒於類型原因,類型零值為0 ), defer無法訪問匿名的傳回值,因此傳回值是0, 而defer還是操作之前定義好的變數i。

試想:如果此處傳回值為指標類型,那麼輸出結果會不會有變化?

 

第二種:命名傳回值

package mainimport ("fmt")func main() {fmt.Println("a return:", a()) // 列印結果為 b return: 2}func a() (i int) {defer func() {i++fmt.Println("a defer2:", i) // 列印結果為 b defer2: 2}()defer func() {i++fmt.Println("a defer1:", i) // 列印結果為 b defer1: 1}()return i // 或者直接 return 效果相同}

輸出結果:

a defer1: 1a defer2: 2a return: 2

解釋: 命名傳回值是 在函式宣告的同時被聲明。因此defer可以訪問命名傳回值。return返回後的值其實是defer修改後的值。

 

defer範圍

defer在什麼環境下就不會執行?下面列舉幾個例子:

1. 當任意一條(主)協程發生 panic 時,會執行當前協程中 panic 之前已聲明的 defer;

func main() {fmt.Println("...")panic(e) // defer 不會執行defer fmt.Println("defer")}

 

2. 主動調用 os.Exit(int) 退出進程時,defer 將不再被執行。

func main() {fmt.Println("...")os.Exit(1) // defer 不會執行defer fmt.Println("defer")}
func main() {fmt.Println("...")defer fmt.Println("defer")os.Exit(1) // defer 不會執行}

 

3.在發生 panic 的(主)協程中,如果沒有一個 defer 調用 recover()進行恢複,則會在執行完之前已聲明的 defer 後,引發整個進程崩潰;

func main() {fmt.Println("...")defer fmt.Println("defer1")defer fmt.Println("defer2")defer fmt.Println("defer3")panic("error") // defer 會執行}

 

4. defer只對當前(主)協程有效

package mainimport ("fmt")func main() {fmt.Println("...")go func() { panic("err") }() // defer 執行defer fmt.Println("defer1")defer fmt.Println("defer2")defer fmt.Println("defer3")}

 

defer的實際用途

無論什麼業務或程式, 延遲都用在執行函數調用的地方。

舉例:

後期更新

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.