Modulelessen (5/5)
`defer`: gegarandeerde opruiming
defer stelt de uitvoering van een oproep ** uit tot de insluitende functie
retourneert**. Het werkt zelfs als de functie via paniek wordt afgesloten. Meerdere defers
in dezelfde functie uitvoeren in LIFO-volgorde (Last-In, First-Out).
Het is het idiomatische mechanisme voor opschonen van bronnen: bestanden sluiten, mutexen ontgrendelen, verbindingen vrijgeven, status herstellen.
Syntaxis en canonieke use-case
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(),
BESCHERMD_INLINE_9.
Argumenten onmiddellijk geëvalueerd, uitvoering uitgesteld
Wanneer u defer foo(x) schrijft, wordt x geëvalueerd op het moment van de
defer, niet tijdens uitvoering:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"LIFO-bestelling
Stelt de stapel uit en voert deze uit, beginnend met de meest recente:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1Dit komt overeen met de semantiek van bronnen: de laatst geopende is de eerste gesloten zijn.
defer + recover: omgaan met paniek
defer is de enige manier om een panic te onderscheppen:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}Valkuil: defer in een lus
Door defer f.Close() in een lus te plaatsen, worden uitstel ** verzameld tot het einde van
de functie**, niet van elke iteratie. In een lange lus open je veel bestanden
en sluit ze pas als de functie wordt afgesloten: risico op lekken van de bestandsdescriptor.
// 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
}Probeer het
Druk 'inizio' af, stel vervolgens de afdruk van 'fijn' uit met uitstel en druk vervolgens 'mezzo' af. De uitvoer moet zijn: inizio / mezzo / fine.
Toon hint
Het uitstel wordt uitgevoerd wanneer main() op het punt staat terug te keren.
Oplossing beschikbaar na 3 pogingen
Schrijf drie opeenvolgende defers met 1, 2 en 3 in die volgorde in de code. De uitvoer is 3 / 2 / 1 (LIFO).
Toon hint
Drie uitstel achter elkaar; onthoud dat ze in omgekeerde volgorde worden uitgevoerd.
Oplossing beschikbaar na 3 pogingen
Wat drukt dit af? (opmerking: uitstelargumenten worden onmiddellijk geëvalueerd)
x := 10
defer fmt.Println(x)
x = 99Samenvatten
defer call()stelt de uitvoering uit totdat de functie terugkeert.- Meerdere uitstel = LIFO-bestelling.
- Argumenten onmiddellijk geëvalueerd, uitvoering uitgesteld.
- Gebruikt voor deterministische opschoning: bestanden, mutexen, verbindingen.
defer+recover()onderschept eenpanic(zeldzaam, op grenzen).- Nooit
deferbinnen een lange lus: deze stapelt zich op totdat de buitenste functie terugkeert.