En Go, les règles de portée des variables (scoping) sont strictement définies par des blocs ({}), et le nom d'une variable peut être masqué (shadowing) dans les zones imbriquées. De nombreux pièges se présentent particulièrement dans les fonctions imbriquées, les fonctions anonymes, les boucles et lors de la déclaration de variables ayant le même nom à différents niveaux.
Go a spécialement minimisé le comportement "magique" avec la portée, afin de rendre le code plus lisible. Cependant, la flexibilité de la syntaxe et la possibilité de redéclarer des variables par la forme courte := entraînent des erreurs de perception.
Si dans une fonction imbriquée ou un bloc de boucle une variable est déclarée avec le même nom que celui du niveau supérieur, la variable externe ne sera pas accessible (masquée – shadowed). Dans la plupart des cas, cela n'est pas remarqué par le compilateur et peut facilement causer des erreurs, en particulier lors du travail avec des closures. Une autre erreur fréquente est de déclarer une nouvelle variable dans un bloc if ou dans for-init, puis d'essayer d'y accéder en dehors du bloc.
Faites toujours attention aux niveaux de portée. N'utilisez pas les mêmes noms de variables dans les blocs imbriqués ou les fonctions anonymes sans réelle nécessité, évitez les noms courts et faites attention à l'utilisation de :=.
Exemple de code:
package main import "fmt" func main() { x := 1 { x := 2 // masque x de main() fmt.Println("Inner x:", x) } fmt.Println("Outer x:", x) for i := 0; i < 3; i++ { x := i // un nouveau x est créé à chaque itération go func() { fmt.Println("Goroutine x:", x) }() } }
Dans cet exemple, la variable externe x n'est pas modifiée, et un nouveau x est créé à l'intérieur du bloc. Dans la seconde boucle, la variable x est capturée dans la fonction imbriquée — le résultat peut être inattendu.
Caractéristiques clés :
:= à l'intérieur d'un bloc crée toujours une nouvelle variable, même si l'externe existe déjà.1. Quelle valeur de la variable sera imprimée en dernier dans le bloc imbriqué lors du masquage ?
La valeur de la variable externe, car la variable interne n'existe que dans le bloc.
2. Que se passe-t-il si l'on essaie d'accéder à une variable déclarée à l'intérieur d'un bloc if/for en dehors de ce bloc ?
Le compilateur renverra une erreur : variable en dehors de la portée.
if true { y := 5 } fmt.Println(y) // erreur
3. Comment éviter une valeur inattendue lors de la création d'une goroutine dans une boucle par rapport à une variable ?
En passant la variable comme paramètre de la fonction :
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
:= modifie une variable déjà existante (elle créera une nouvelle variable).La boucle initialise plusieurs goroutines pour un traitement parallèle, mais à l'intérieur de la closure, la variable de boucle est utilisée sans transmission — toutes les goroutines travaillent avec sa "dernière" valeur.
Avantages :
Inconvénients :
Passer la variable de boucle comme paramètre de la closure — chaque goroutine reçoit sa propre valeur.
Avantages :
Inconvénients :