ProgrammazioneSviluppatore Go

Spiega come funziona defer in Go e quando l'ordine delle chiamate potrebbe diventare sorprendente. Quali insidie si possono incontrare nella pratica?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

La parola chiave defer in Go ritarda l'esecuzione delle funzioni specificate fino all'uscita dalla funzione circostante: le funzioni si accumulano nello stack e vengono eseguite in ordine inverso (LIFO). Questo viene spesso utilizzato per liberare risorse (file, mutex, connessioni).

Una caratteristica è che tutti gli argomenti delle funzioni passate a defer vengono calcolati immediatamente al momento della dichiarazione, e non durante l'esecuzione.

func test() { for i := 0; i < 3; i++ { defer fmt.Println(i) // Stamperà: 2, 1, 0 } }

Domanda insidiosa.

Cosa stamperà il seguente codice?

func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) } }

Risposta:

Questo stamperà:

2
1
0

Perché in ogni ciclo l'argomento i viene calcolato immediatamente (al momento di defer), e tutti i valori vengono memorizzati nello stack dei defer.

Esempi di errori reali a causa della mancata conoscenza delle sottigliezze dell'argomento.


Storia

In un servizio file hanno dimenticato di considerare che defer viene chiamato solo durante l'uscita normale dalla funzione. Ci sono state perdite se il programma è terminato in modo anomalo prima del punto di chiamata defer.


Storia

In una pipeline di dati si è dimenticato — nel ciclo si utilizzava defer per chiudere le connessioni, ma di fatto si chiudevano solo dopo il completamento dell'intera funzione, e non dopo ogni iterazione. Questo ha portato all'esaurimento delle risorse.


Storia

Nel logger si utilizzava defer con una funzione anonima, aspettandosi che l'argomento venisse calcolato al momento della chiamata. Di conseguenza, il log alla fine conteneva informazioni obsolete, poiché i valori venivano catturati prima.