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