ProgrammationIngénieur backend Go

Expliquez comment fonctionne le mécanisme range en Go lors de l'utilisation de map et slice. Quelles sont les subtilités de l'utilisation des variables de boucle et quelles erreurs peut-on rencontrer ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

La boucle for ... range permet de parcourir facilement les éléments d'un slice, d'une map, d'un tableau ou d'une chaîne.

  • Pour slice : à chaque itération, elle retourne l'index et une copie de l'élément.
  • Pour map : elle retourne la clé et une copie de la valeur.

Exemple :

s := []int{1, 2, 3} for i, v := range s { fmt.Println(i, v) } m := map[string]int{"a":1, "b":2} for k, v := range m { fmt.Println(k, v) }

Subtilité clé : Les variables i, v, k, etc. sont réutilisées à chaque itération ! Cela devient souvent une source de bogues lors du passage de celles-ci par référence à l'intérieur de la boucle ou lors du lancement de goroutines à l'intérieur de range.

Question piégeuse

Que se passe-t-il si, à l'intérieur de range sur un slice, une goroutine est lancée en capturant la variable d'itération ? Comment éviter l'erreur ?

Réponse : Une erreur typique se produit : au sein de la goroutine, les variables de boucle sont utilisées, qui, après la fin de la boucle, auront la dernière valeur. Pour éviter cela, il faut créer des copies locales :

nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }

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


Histoire

Dans un projet, nous avons utilisé range pour remplir un slice à travers plusieurs goroutines, oubliant de faire des copies des variables de boucle. Toutes les goroutines ont imprimé la même valeur - la dernière du tableau, ce qui a fortement altéré la logique métier.


Histoire

Lors de l'utilisation de range sur une map, un pointeur vers la valeur a été enregistré dans un nouveau slice de pointeurs. En conséquence, tous les éléments du nouveau slice faisaient référence à la même variable - celle utilisée dans la boucle (copie de la valeur). Le bogue est apparu lors de la mise à jour de ces variables en dehors de la boucle (panic : adresse mémoire invalide ou données inattendues).


Histoire

Dans un outil interne, en utilisant range sur une chaîne, j'ai lancé des gestionnaires de sous-chaînes significatives, mais à chaque itération, j'ai obtenu un décalage en octets, et non en caractères Unicode. Résultat : traitement incorrect pour les chaînes Unicode, découpage incorrect des caractères.