Lektionen des Moduls (5/5)
defer: garantierte Bereinigung
defer verschiebt die Ausführung eines Aufrufs bis zur umschließenden Funktion
kehrt zurück. Es wird auch dann ausgeführt, wenn die Funktion per Panik beendet wird. Mehrere defers
in derselben Funktion in LIFO-Reihenfolge ausführen (Last-In, First-Out).
Es ist der idiomatische Mechanismus für die Ressourcenbereinigung: Dateien schließen, Mutexe entsperren, Verbindungen freigeben, Zustand wiederherstellen.
Syntax und kanonischer Anwendungsfall
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nilTypisch: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(),
recover().
Argumente sofort ausgewertet, Ausführung verschoben
Wenn Sie defer foo(x) schreiben, wird x zum Zeitpunkt des ausgewertet
defer, nicht zum Ausführungszeitpunkt:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"LIFO-Auftrag
Verschiebt das Stapeln und Ausführen, beginnend mit dem aktuellsten:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1Dies steht im Einklang mit der Ressourcensemantik: Das zuletzt Geöffnete ist das Erste geschlossen werden.
defer + recover: Umgang mit Panik
defer ist die einzige Möglichkeit, einen panic abzufangen:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}Fallstrick: defer in einer Schleife
Wenn Sie defer f.Close() in eine Schleife einfügen, werden Verzögerungen bis zum Ende akkumuliert
die Funktion**, nicht jeder Iteration. In einer langen Schleife öffnen Sie viele Dateien
und schließen Sie sie erst, wenn die Funktion beendet wird: Es besteht die Gefahr eines Dateideskriptorlecks.
// MALE: defer accumulati
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // chiude TUTTI alla fine della funzione esterna
// ...
}
// MEGLIO: estrai in una funzione
for _, path := range paths {
elabora(path) // ogni chiamata ha il proprio scope di defer
}Probieren Sie es aus
Geben Sie „inizio“ ein, verzögern Sie dann den Ausdruck von „fine“ mit „defer“ und geben Sie dann „mezzo“ aus. Die Ausgabe muss sein: inizio / mezzo / fine.
Hinweis anzeigen
Die Verzögerung wird ausgeführt, wenn main() kurz vor der Rückkehr steht.
Lösung nach 3 Versuchen verfügbar
Schreiben Sie drei aufeinanderfolgende Verzögerungen, die 1, 2 und 3 in dieser Reihenfolge im Code ausgeben. Die Ausgabe erfolgt 3/2/1 (LIFO).
Hinweis anzeigen
Drei Aufschübe nacheinander; Denken Sie daran, dass sie in umgekehrter Reihenfolge ausgeführt werden.
Lösung nach 3 Versuchen verfügbar
Was wird hier gedruckt? (Hinweis: Verzögerungsargumente werden sofort ausgewertet)
x := 10
defer fmt.Println(x)
x = 99Zusammenfassung
defer call()verschiebt die Ausführung, bis die Funktion zurückkehrt.- Mehrere Verzögerungen = LIFO-Reihenfolge.
- Argumente sofort bewertet, Ausführung verschoben. – Wird zur deterministischen Bereinigung verwendet: Dateien, Mutexe, Verbindungen.
defer+recover()fängt einenpanicab (selten, an Grenzen).- Niemals
deferinnerhalb einer langen Schleife: Es sammelt sich an, bis die äußere Funktion zurückkehrt.