ProgrammationDéveloppeur Backend

Comment les fermetures (closures) sont-elles réalisées en Go, quels pièges sont associés à leur utilisation lors du lancement de goroutines à l'intérieur de boucles, et comment éviter les erreurs typiques ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Go, les fermetures (closures) sont des fonctions qui "capturent" les variables de leur portée environnante. Les fermetures sont le plus souvent utilisées pour des fonctions anonymes créées à l'intérieur d'autres fonctions.

Le problème le plus typique lors de l'utilisation des fermetures est le comportement inattendu lors de l'utilisation des variables de boucle à l'intérieur d'une goroutine :

for i := 0; i < 3; i++ { go func() { fmt.Println(i) }() }

Chaque goroutine peut imprimer la même valeur i, car la variable i est cyclique, et la fermeture capture la variable elle-même, et non sa valeur à chaque itération.

Méthode correcte :

for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }

Ce comportement est dû au fait que la fermeture conserve une référence à la variable (son adresse), et non à sa valeur copiée.

Question piège

Quelle valeur imprimeront plusieurs goroutines lancées dans une boucle si elles capturent la variable de boucle ?

Réponse : Toutes les goroutines peuvent imprimer la même valeur (souvent la dernière), car elles voient la valeur actuelle de la variable, et à l'époque de l'exécution de la goroutine, la boucle est déjà terminée. Pour éviter cela, la variable doit être passée comme paramètre à la fermeture.

Exemple :

for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } // nous obtiendrons probablement : 5 5 5 5 5

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


Histoire

Dans le système d'analyse produit, les données étaient anonymisées dans des goroutines parallèles à l'aide d'une fermeture capturant la variable de boucle. En conséquence, toutes les tâches parallèles traitaient le même ensemble de données - ce qui a entraîné une distorsion des statistiques et une reporting incorrecte.

Histoire

Dans un service cloud d'intégrations backend en Go, les équipes ont décidé d'optimiser la collecte des métriques en lançant leur traitement dans une boucle à l'aide de fonctions anonymes - à l'intérieur de la goroutine, elles ont capturé l'index de la map, résultat : une partie des gestionnaires collectait des données non pas pour leurs services, mais pour le dernier index traité.

Histoire

Dans une startup de livraison, l'utilisation incorrecte des fermetures lors de la mise à jour des coordonnées de commande entraînait la mise à jour massive des coordonnées de la dernière commande dans le tableau, et non de la commande actuelle - en raison de la concurrence lors de l'accès au tableau à l'intérieur de la fonction anonyme.