ProgrammationDéveloppeur Go

Expliquez comment fonctionne defer en Go et quand l'ordre des appels peut devenir une surprise. Quelles sont les pièges que l'on rencontre en pratique ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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 } }

Question piège.

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.

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


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.