Menu

Variables en Golang : var, :=, valeurs zéro et masquage

Comment déclarer des variables en Go avec var et la forme courte :=, ce que sont les valeurs zéro, l'affectation multiple, et les erreurs de masquage et de variable inutilisée qui piègent les nouveaux développeurs Go.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Go a deux façons de déclarer une variable : var, qui fonctionne partout, et :=, une forme courte qui fonctionne dans les fonctions et déduit le type.

Chaque variable a un type fixe décidé à la compilation. Quand vous donnez une valeur, Go en déduit le type, donc écrire aussi le type (var city string = "Lisbon") est légal mais redondant.

var ou :=

var:=
au niveau du package et dans les fonctionsuniquement dans les fonctions
Typefacultatif ; obligatoire sans valeurtoujours déduit
Valeur initialefacultative (valeur zéro sinon)obligatoire
Redéclarationjamaispermise si au moins une variable à gauche est nouvelle

Le choix idiomatique dans une fonction :

  • x := value quand vous avez une valeur de départ.
  • var x T quand vous voulez la valeur zéro, ce qui signale « vide exprès » : var buf bytes.Buffer, var total int.
  • var x T = value quand le type déduit n'est pas celui que vous voulez, par exemple var ratio float64 = 1 (un simple ratio := 1 serait un int).

:= hors d'une fonction est une erreur de syntaxe :

./main.go:5:1: syntax error: non-declaration statement outside function body

Valeurs zéro

Une variable déclarée sans valeur ne contient jamais n'importe quoi. Elle contient la valeur zéro de son type :

TypeValeur zéro
entiers, flottants0
boolfalse
string""
pointeurs, slices, maps, channels, fonctions, interfacesnil
tableaux, structschaque élément ou champ à sa valeur zéro

Les bonnes API Go sont conçues pour que la valeur zéro soit utile : un sync.Mutex à zéro est déverrouillé, un bytes.Buffer à zéro est vide et prêt, et len, range et append fonctionnent tous sur une slice nil. Celle à surveiller est la map : lire une map nil renvoie des valeurs zéro, mais y écrire provoque un panic. Créez les maps avec make ou un littéral avant d'y stocker quoi que ce soit.

Déclarer plusieurs variables

Le bloc var ( ... ) regroupe des variables liées au niveau du package. Dans une affectation multiple comme x, y = y, x, chaque expression à droite est évaluée avant toute affectation, c'est pourquoi l'échange fonctionne.

:= avec plusieurs noms ne redéclare rien tant qu'au moins un nom à gauche est nouveau. Les noms existants dans la même portée sont simplement affectés. C'est ce qui permet de réutiliser err :

f, err := os.Open("a.txt")   // declares f and err
g, err := os.Open("b.txt")   // declares g, assigns to the existing err

Si aucun des noms n'est nouveau, c'est une erreur :

./main.go:7:4: no new variables on left side of :=

Utilisez un simple = pour affecter une variable qui existe déjà.

Les variables inutilisées sont des erreurs

Une variable locale déclarée mais jamais lue arrête le build :

./main.go:9:2: declared and not used: x

Ce n'est pas un avertissement que l'on peut désactiver. Supprimez la variable, utilisez-la, ou, pendant le débogage, faites-la taire avec l'identifiant blanc : _ = x. L'identifiant blanc sert aussi à jeter les valeurs de retour dont vous n'avez pas besoin : _, err := fmt.Println("hi").

Les variables au niveau du package et les paramètres de fonction échappent à cette règle.

Portée et masquage

Une variable existe de sa déclaration jusqu'à la fin du bloc englobant ({ ... }). Un := dans un bloc intérieur crée une nouvelle variable, même si une variable du même nom existe à l'extérieur. Celle de l'extérieur est masquée, pas modifiée :

Le programme affiche inside: 42 puis outside: 0. Le := à l'intérieur du if a déclaré count et err comme nouvelles variables dans le bloc intérieur, parce qu'aucune n'y existait encore. Cela compile sans problème et c'est une source classique de bugs du genre « ma valeur a disparu ».

La correction consiste à déclarer err d'abord et à affecter avec = :

var err error
count, err = strconv.Atoi(input)

go vet ne signale pas le masquage par défaut. L'analyseur séparé shadow le fait, et des linters comme golangci-lint peuvent l'activer.

Nommage

  • Utilisez le camelCase : maxRetries, userID. Pas max_retries.
  • Gardez les acronymes dans une seule casse : userID, httpClient, parseURL, pas userId.
  • Des noms courts pour des portées courtes : i dans une boucle, r pour un reader, err pour une erreur. Des noms plus longs et descriptifs pour les variables au niveau du package.
  • Un nom en majuscule au niveau du package (var Timeout) est exporté vers les autres packages. Voir packages et imports.

Variables au niveau du package

Les variables déclarées hors des fonctions vivent pendant tout le programme et sont initialisées avant l'exécution de main, dans l'ordre des dépendances. Elles sont pratiques pour la configuration et les caches, et elles sont partagées par toutes les goroutines. Si plus d'une goroutine y écrit, protégez-la avec un mutex ou utilisez sync/atomic, sinon vous avez une data race.

Préférez les constantes pour les valeurs qui ne changent jamais. Une const ne peut pas être modifiée par accident et ne coûte rien à l'exécution.

Questions fréquentes

Quelle est la différence entre var et := en Go ?

:= déclare et initialise une variable avec un type déduit, et ne fonctionne que dans les fonctions : count := 10. var fonctionne partout (y compris au niveau du package), permet d'indiquer le type, et peut omettre la valeur initiale pour obtenir la valeur zéro : var count int. Dans les fonctions, le Go idiomatique utilise := quand il y a une valeur initiale et var quand on veut la valeur zéro.

Que sont les valeurs zéro en Go ?

Toute variable déclarée sans valeur reçoit la valeur zéro de son type : 0 pour les nombres, false pour bool, "" pour string, et nil pour les pointeurs, slices, maps, channels, fonctions et interfaces. Les structs reçoivent la valeur zéro de chaque champ. Go n'a pas de variables non initialisées.

Comment corriger « declared and not used » en Go ?

Go refuse une variable locale qui est affectée mais jamais lue. Utilisez-la, supprimez-la, ou, pendant le débogage, affectez-la à l'identifiant blanc avec _ = x. Les variables au niveau du package et les paramètres de fonction ne sont pas concernés.

Comment déclarer une variable globale en Go ?

Utilisez var au niveau du package, hors de toute fonction : var counter int. La forme courte := n'y est pas permise. Un nom en majuscule (var Counter int) est visible par les autres packages ; un nom en minuscule n'est visible que dans son propre package. Protégez les variables au niveau du package avec un mutex si des goroutines y écrivent.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER