2016-05-06 6 views
5

Ich habe über eine answer auf eine Frage über „Rückwärtsbereich“ laufen und ich wollte es nach unten Abstimmung, wie es lächerlich falsch schien aber überprüft und es tatsächlich funktioniert (!):Go: Warum wird die Verschiebung in der Range-Schleife in umgekehrter Reihenfolge aufgerufen?

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]) 
    } 
} 

Und der Ausgang ist:

5 
4 
3 
2 
1 
Program exited. 

Irgendwelche Ideen, warum es so funktioniert? Habe ich Recht, es ist nicht garantiert, dass es genau in der umgekehrten Reihenfolge ausgeführt wird? Ich denke auch nicht, dass es ein guter Weg ist, Programme zu schreiben, aber neugierig zu finden, warum wir dieses Ergebnis bekommen.

Antwort

7

defer ist ein LIFO, oder ein Stapel - es wird garantiert in umgekehrter Reihenfolge ausgeführt. Es bekommt die erste defer und legt es auf einen internen Stack (wahrscheinlich kenne ich die blutigen Details nicht), und setzt dann die nächste defer auf diese, und wenn es das Ende der Funktion erreicht, wird es abgewickelt , beginnend an der Spitze. Es scheint in einem for -loop erfunden (ich weiß, das ist Gos Beispiel, nicht deins), aber in anderen Fällen, wo eine Funktion von der Aufräumung einer anderen Funktion abhängt, macht es mehr Sinn, warum es sein sollte und daher ist , garantiert umgekehrte Reihenfolge der Ausführung.

Hier ist ein anderes Beispiel, alle Pseudo-Code, aber hoffentlich ist der Punkt klar.

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" 

Sollte drucken etwas wie:

"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..." 

Wenn Sie keine Garantien für Reverse-Bestellung hatte, konnte man nicht sicher sein, stream1 während Ihres defer stream2 write noch offen war.

+0

Danke, es macht total Sinn jetzt. Aber innerhalb einer Schleife für den umgekehrten Fall zu verwenden ist ziemlich schwierig und sollte in Bezug auf die Speicherkapazität ziemlich ineffektiv sein. –

+1

Ja, ich erinnere mich, dass ich von diesem play.golang-Beispiel nicht begeistert war, weil es so konstruiert ist, dass es verwirrend ist, und es hat nicht wirklich verstanden, warum es umgekehrt sein sollte. Froh, dass ich helfen konnte! – dwanderson

Verwandte Themen