2016-05-06 45 views
5

我已經跨越answer上關於「逆範圍」的問題跑,我要向下票,因爲它看起來非常錯誤的,但檢查和它的實際工作(!):轉:爲什麼推遲範圍循環以相反順序調用?

https://play.golang.org/p/4K2fDlSoCm

package main 

import (
    "fmt" 
) 

func main() { 
    s := []int{1, 2, 3, 4, 5} 
    for i, _ := range s { 
     defer fmt.Println(s[i]) 
    } 
} 

,輸出是:

5 
4 
3 
2 
1 
Program exited. 

任何想法,爲什麼是這樣工作的?我是否確定它不能完全按照相反的順序執行?另外我不認爲這是編寫程序的好方法,但很好奇爲什麼我們會得到這個結果。

回答

7

defer是一個LIFO,或一個堆棧 - 它保證以相反的順序執行。它得到第一個defer,並把它放在一些內部堆棧上(可能我不知道血淋淋的細節),然後把下一個defer放在那個之上,然後當它到達函數結尾時,它解開,從頂部開始。它看起來像是在for -loop(我知道這是Go的例子,不是你的),但在其他情況下,其中一個函數依賴於某個其他函數的清理,它更有意義,爲什麼它應該是,因此IS ,保證是相反的執行順序。

下面是一個不同的例子,所有的僞代碼,但希望這一點是明確的。

open stream1 
defer close stream1 
defer write stream1 "stream2 better be closed, or we are in trouble..." 
open stream2 
defer close stream2 
defer stream2 "this is the last you'll ever hear from stream2" 

connect stream2 to stream1 

write stream2 "hey, we are in stream2, this feeds into stream1" 

應打印一樣的東西:

"hey, we are in stream2, this feeds into stream1" 
"this is the last you'll ever hear from stream2" 
"stream2 better be closed, or we are in trouble..." 

如果你沒有對反向排序保證,你也不能肯定stream1defer stream2 write期間仍然開放。

+0

謝謝,現在完全有意義。但是,在循環內使用反向操作非常棘手,應該是非常有效的記憶方式。 –

+1

是的,我記得不會因爲那個play.golang的例子而激動不已,因爲它太容易混淆了,它並沒有真正理解爲什麼它應該是相反的。很高興我能幫上忙! – dwanderson