Go語言的defer,你真的懂了嗎?

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

2013-04-25

Go語言的defer,你真的懂了嗎?

example1

func f() (result int) {    defer func() {        result++    }()    return 0}

example2

func f() (r int) {     t := 5     defer func() {       t = t + 5     }()     return t}

example3

func f() (r int) {    defer func(r int) {          r = r + 5    }(r)    return 1}

先不要運行代碼,自己在心裡跑一遍結果,然後再去驗證。如果三個都做對了並且不好蒙的...好吧,不用往下看了,你已經懂defer了。

額,如果example1中你算的是0,你就錯了;如果example2中你覺得是10,你又錯了...蒙對的不算...如果example3中覺得得6,你又錯了...如果你有算對的,也有算錯,好吧...你丫的就是在蒙!不懂的繼續往下看啊.....

首先要明確的是:defer是在return之前執行的。這個在 官方文檔中明確說明了的。

然後是瞭解defer的實現方式,大致就是在defer出現的地方,插入指令CALL runtime.deferproc,然後在函數返回之前的地方,插入指令CALL runtime.deferreturn。再就是明確go傳回值的方式跟C是不一樣的,為了支援多值返回,go是用棧傳回值的,而C是用寄存器。

最最重要的一點就是: *return xxx這一條語句並不是一條原子指令!*

整個return過程,沒有defer之前,先在棧中寫一個值,這個值會被當作傳回值,然後再調用RET指令返回。return xxx語句彙編後是先給傳回值賦值,再做一個空的return,( 賦值指令 + RET指令)。defer的執行是被插入到return指令之前的,有了defer之後,就變成了(賦值指令 + CALL defer指令 + RET指令)。而在CALL defer函數中,有可能將最終的傳回值改寫了...也有可能沒改寫。總之,如果改寫了,那麼看上去就像defer是在return xxx之後執行的~

這是所有你所想不明白的defer故事發生的根源。

上面的基礎知識都有了,然後就可以說說神奇的defer了。告訴大家一個簡單的轉換規則大家就再也不為defer迷糊了。改寫規則是將return語句分開成兩句寫,return xxx會被改寫成:

傳回值 = xxx調用defer函數空的return

先看example1,它可以改寫成這樣:

func f() (result int) {     result = 0  //return語句不是一條原子調用,return xxx其實是賦值+RET指令     func() { //defer被插入到return之前執行,也就是賦傳回值和RET指令之間         result++     }()     return}

所以這個傳回值是1。

再看example2,它可以改寫成這樣:

func f() (r int) {     t := 5     r = t //賦值指令     func() {        //defer被插入到賦值與返回之間執行,這個例子中傳回值r沒被修改過         t = t + 5     }     return        //空的return指令}

所以這個的結果是5。

最後看example3,它改寫後變成:

func f() (r int) {     r = 1  //給傳回值賦值     func(r int) {        //這裡改的r是傳值傳進去的r,不會改變要返回的那個r值          r = r + 5     }(r)     return        //空的return}

所以這個例子的結果是1。

懂了嗎? 結論:defer確實是在return之前調用的。但表現形式上卻可能不像。本質原因是return xxx語句並不是一條原子指令,defer被插入到了賦值 與 RET之前,因此可能有機會改變最終的傳回值。當你覺得迷糊時,可以用我給的這套規則轉一下代碼。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.