Le mot-clé defer en Go retarde l'exécution des fonctions spécifiées jusqu'à la sortie de la fonction englobante — les fonctions s'accumulent dans la pile et s'exécutent dans l'ordre inverse (LIFO). Cela est souvent utilisé pour libérer des ressources (fichiers, mutex, connexions).
Une caractéristique est que tous les arguments des fonctions passées à defer sont calculés immédiatement au moment de la déclaration, et non lors de l'exécution.
func test() { for i := 0; i < 3; i++ { defer fmt.Println(i) // Affichera : 2, 1, 0 } }
Que va afficher le code suivant ?
func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) } }
Réponse :
Cela affichera :
2
1
0
Parce que pour chaque itération, l'argument i est calculé immédiatement (au moment du defer), et toutes les valeurs sont stockées dans la pile des defer.
Histoire
Dans un service de fichiers, on a oublié de prendre en compte que defer n'est appelé qu'en cas de sortie normale de la fonction. Des fuites sont apparues si le programme se terminait de manière inattendue avant le point d'appel de defer.
Histoire
Dans un pipeline de données, on a oublié — dans une boucle, on a utilisé defer pour fermer les connexions, mais en réalité, elles ne se fermaient qu'après l'achèvement de toute la fonction, et non après chaque itération. Cela a conduit à l'épuisement des ressources.
Histoire
Dans le logger, on a utilisé defer avec une fonction anonyme, s'attendant à ce que l'argument soit calculé au moment de l'appel. Cela a conduit à ce que le log à la fin contienne des informations obsolètes, car les valeurs étaient capturées plus tôt.