Defer 的變量快照什么情況會失效?
本篇問題:Go 中閉包的底層原理?
關于 defer 的基本知識點,我在以前的教程中有寫過:14. Go語言流程控制:defer 延遲調用
其中有一個知識是 defer 的變量快照,舉個簡單的例子來說
在下面這段代碼中,會先打印出來 18,即使后面 age 已經被改變了,可 defer 中的 age還是 修改之前的 0,這種現(xiàn)象稱之為變量快照。
- func func1() {
- age := 0
- defer fmt.Println(age) // output: 0
- age = 18
- fmt.Println(age) // output: 18
- }
- func main() {
- func1()
- }
對于這個輸出結果,相信還是挺容易理解的。
接下來,我請大家再看下面這個例子,可以猜猜看會輸出什么?
- func func1() {
- age := 0
- defer func() {
- fmt.Println(age)
- }()
- age = 18
- return
- }
- func main() {
- func1()
- }
正確的答案是:18, 而不是 0
你肯定會納悶:不對啊,defer 不是會對變量的值做一個快照嗎?答案應該是 0 啊,為什么會是 18?
實際上,仔細觀察,可以發(fā)現(xiàn)上面的兩個例子的區(qū)別就在于,一個 defer 后接的是單個表達式,另一個 defer 后接的是一個函數(shù),并且不是普通函數(shù),而是一個匿名的閉包函數(shù)。
根據(jù)閉包的特性,實際上在閉包函數(shù)存的是 age 這個變量的指針(原因可以查看上一篇文章:Go 面試題 013:Go 中閉包的底層原理是?),因而,在 defer 后所修改的值會直接影響到 defer 中的 age 的值。
總結一下:
- 若 defer 后接的是單行表達式,那defer 中的 age 只是拷貝了 func1 函數(shù)棧中 defer 之前的 age 的值;
- 若 defer 后接的是閉包函數(shù),那defer 中的 age 只是存儲的是 func1 函數(shù)棧中 age 的指針。
本文轉載自微信公眾號「Go編程時光」,可以通過以下二維碼關注。轉載本文請聯(lián)系Go編程時光公眾號。