2016-05-06 22 views
5

Ho eseguito attraverso un answer su una questione di "gamma inversa" e mi stava per down-voto come sembrava ridicolmente sbagliato, ma controllato e in realtà funziona (!):Vai: Perché il rinvio del ciclo di intervallo viene chiamato in ordine inverso?

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

e l'uscita è:

5 
4 
3 
2 
1 
Program exited. 

Tutte le idee perché funziona in questo modo? Ho ragione, non è garantito che venga eseguito esattamente nell'ordine inverso? Inoltre, non penso che sia un buon modo per scrivere programmi ma curioso di scoprire perché stiamo ottenendo questo risultato.

risposta

7

defer è un LIFO o uno stack: è garantito l'esecuzione in ordine inverso. Ottiene il primo defer e lo mette su uno stack interno (probabilmente, non conosco i dettagli cruenti), quindi inserisce il successivo defer sopra quello e, quando raggiunge la fine della funzione, si srotola , iniziando dall'alto. Sembra forzato in uno for -loop (so che questo è l'esempio di Go, non il tuo), ma in altri casi in cui una funzione dipende dalla ripulitura di qualche altra funzione, ha più senso perché DOVREBBE essere, e quindi IS , garantito come ordine di esecuzione inverso.

Ecco un esempio diverso, tutto pseudo-codice, ma si spera che il punto sia chiaro.

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" 

dovrebbe stampare qualcosa di simile:

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

Se non si dispone di garanzie su ordinazione inverso, non si poteva essere sicuri stream1 era ancora aperta durante il vostro defer stream2 write.

+0

Grazie, ora ha senso. Ma usare all'interno di un ciclo per il reverse è piuttosto complicato e dovrebbe essere piuttosto inefficace dal punto di vista della memoria. –

+1

Sì, ricordo di non essere entusiasta di quell'esempio di play.golang, perché è così inventato da essere confuso e non capisco perché debba essere invertito. Felice di poterti aiutare! – dwanderson