Historisch gezien is het concept defer geïntroduceerd in Go voor veilige vrijgave van middelen en finalisatie van acties, ongeacht hoe de uitvoering van de functie is beëindigd (normaal of door panic). Echter, de interactie van defer met return en panic heeft enkele vervelende valkuilen die vaak worden over het hoofd gezien, zelfs door ervaren ontwikkelaars.
Probleem is dat de volgorde van berekening van terug te geven waarden, het werken met named return values en het wijzigen van deze waarden in defer sterk verschilt van het gebruikelijke gedrag in veel andere talen. Bovendien kunnen fouten optreden als er in defer geprobeerd wordt al berekende waarden te wijzigen, wat onverwacht gedrag kan veroorzaken.
Oplossing — onthoud altijd: de waarden die de functie retourneert, worden BEREKEND VOOR de defer wordt uitgevoerd, maar als genummerde resultaten worden gebruikt, kunnen ze binnen defer worden gewijzigd vóór de feitelijke terugkeer uit de functie.
Voorbeeldcode:
func tricky() (res int) { defer func() { res = 42 // Wijzigt de geretourneerde waarde! }() return 10 } func main() { fmt.Println(tricky()) // Geeft 42 weer, niet 10 }
Belangrijkste kenmerken:
In welke volgorde worden uitgestelde (defer) functies uitgevoerd?
Ze worden strikt in omgekeerde volgorde van hun declaratie uitgevoerd (stack — LIFO).
func f() { defer fmt.Println("1") defer fmt.Println("2") } // Geeft: 2, dan 1
Wanneer worden de parameters voor defer-functies berekend — op het moment van declaratie van defer of bij de uitvoering ervan?
De parameters voor de defer-functie worden berekend op het moment van declaratie van defer, en niet bij de aanroep.
func f() { i := 1 defer fmt.Println(i) // zal 1 weergeven, zelfs als i later verandert i = 2 }
Kan defer een niet-genummerd resultaat van een functie wijzigen?
Nee. Alleen genummerde terug te geven waarden kunnen binnen defer worden gewijzigd.
func f() int { defer func() { /* niets wijzigen */ }() return 5 }
Een jonge ontwikkelaar wilde de return-code in defer loggen en wijzigde per ongeluk de genummerde teruggegeven waarde, waardoor het werkelijke resultaat van de functie werd "overschreven".
Voordelen:
Nadelen:
In een andere situatie werd defer alleen gebruikt voor het vrijgeven van middelen, logging en wijzigde niet de return, terwijl belangrijke waarden expliciet werden toegewezen vóór return.
Voordelen:
Nadelen: