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.
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
Histoire
Histoire
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.