你真的懂defer了嗎

2021-06-17 18:34:48 字數 1788 閱讀 7005

example1

func f() (result int) ()

return 0

}

example2

func f() (r int) ()

return t

}

example3

func f() (r int) (r)

return 1

}

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

多空幾行確保你先在心裡跑過一遍**,之後驗證了,並且存在疑惑......

額,如果example1中你算的是0,你就錯了

如果example2中你覺得是10,你又錯了...矇對的不算...

不懂的繼續往下看啊.....

首先要明確的是:defer是在return之前執行的

這是官方文件中明確說明的

,知道就行了,可以無視

然後要了解是的defer的實現方式,我以前有寫過

大意就是在defer出現的地方插入的指令

call runtime.deferproc

然後在函式返回之前的地方,插入指令

call runtime.deferreturn

再就是明確go返回值的方式跟c是不一樣的,為了支援多值返回,go是用棧返回值的,而c是用暫存器。

最最最重要的一點就是:

return *** 這一句語句並不是一條原子指令

!整個return過程,沒有defer之前是,先把在棧中寫乙個值,這個值被會當作返回值。然後再呼叫ret指令返回。return ***語句彙編後是先給返回值賦值,再做乙個空的return: ( 賦值指令 + ret指令)

defer的執行是被插入到return指令之前的

有了defer之後,就變成了 (賦值指令 + call defer指令 + ret指令)

而在call defer函式中,有可能將最終的返回值改寫了...也有可能沒改寫。總之,如果改寫了,那麼看上去就像defer是在return ***之後執行的~

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

上面的基礎知識都有了,然後就可以來說說神奇的defer了。告訴大家乙個簡單的轉換規則大家就再也不為defer迷糊了。

改寫規則是將return語句分開成兩句寫,return ***會被改寫成:

返回值 = ***

呼叫defer函式

空的return

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

func f() (result int) ()

return

}

所以這個返回的是1

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

func f() (r int) 

return //空的return指令

}

所以這個的結果是5

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

func f() (r int) (r)

return //空的return

}

所以這個例子結果是1

懂了麼?

結論:defer確實是在return之前呼叫的。但表現形式上卻可能不像。本質原因是return ***語句並不是一條原子指令,defer被插入到了賦值 與 ret之前,因此可能有機會改變最終的返回值。

當你覺得迷糊時,可以用我給的這套規則轉一下**。

**:

你真的懂學習麼?

目錄 why what how 小結 為啥要學習呢?如果你想變得更優秀,除了學習,你還有其他選擇麼?除了學習,你別無選擇。什麼是學習?官方解釋 個體由經驗或練習引起的在能力或傾向方面的變化,也指變化的過程。是人類和動物普遍具有的活動。按內容可分為認知的 情感的 運動技能的 按是否理解可分為機械學習和...

你真的懂迴圈嗎

好了今天我來講講什麼是迴圈吧,你又真的懂迴圈嗎?讓我來講講迴圈的細節吧和判斷吧 1 for迴圈樣式 for var i 0 i 5 i 它的條件表示式就是先寫for 在寫內部的條件,在js中宣告變數也是可以不加var直接就可以 for i 0 i 5 i 但這樣寫也有一點不對,因為i時區域性變數最好...

你真的懂程式設計嗎?

還記得自己剛學習程式設計的時候,是在大一學習c語言的時候,那時在學習程式設計的時候,一遇到一些問題就開始在網上或者書上找有沒有現成的程式。找到後就把它們稍作修改從而實現自己想要的功能,以為這就是程式設計。到後面自己學習微控制器程式設計的時候也是這樣,雖然我可以實現功能。但是就是感覺自己其實也沒做多少...