Une constante est une valeur fixée à la compilation. Déclarez-la avec const, et Go refuse toute tentative de la modifier.
Les constantes peuvent être déclarées au niveau du package ou dans une fonction, une par ligne ou regroupées dans un bloc const ( ... ). MB et GB sont calculées à partir d'autres constantes, et le compilateur fait ce calcul une seule fois, à la compilation.
Affecter une valeur à une constante, comme MaxRetries = 5, est une erreur de compilation :
./main.go:8:2: cannot assign to MaxRetries (neither addressable nor a map index expression)
Ce qui peut être une constante
Seulement trois sortes de valeurs : les booléens, les nombres (entiers, flottants, nombres complexes et runes) et les chaînes. La valeur doit pouvoir être calculée par le compilateur, c'est-à-dire des littéraux, d'autres constantes, de l'arithmétique sur celles-ci, et quelques fonctions intégrées comme len d'une chaîne constante.
Tout ce qui exige d'exécuter du code ou d'allouer de la mémoire est exclu :
const Colors = []string{"red", "green"} // slice
const Started = time.Now() // function call
./main.go:9:16: []string{…} (value of type []string) is not constant
./main.go:10:13: time.Now() (value of struct type time.Time) is not constant
Pourquoi Go n'a pas de slices ni de maps constantes
Les slices, les maps et les structs qui en contiennent sont des références vers de la mémoire qui existe à l'exécution, donc le compilateur ne peut pas les intégrer au programme comme valeurs fixes, et Go n'a pas de modificateur readonly ou final pour les variables. Les contournements courants :
La copie coûte une allocation par appel, ce qui convient pour des données de la taille d'une configuration. Pour une recherche par clé, un switch dans une fonction est une autre option qui se comporte comme une constante : func statusText(code int) string { switch code { ... } }.
Constantes non typées
Une constante déclarée sans type est non typée. Elle a une catégorie (entier, flottant, rune, chaîne, bool) mais pas de type Go précis tant qu'elle n'est pas utilisée, et elle s'adapte au contexte :
Ratio fonctionne comme un int, un float64, un uint8 et un float32 sans conversion. C'est pour cela que time.Sleep(2 * time.Second) compile : 2 est non typé et devient un time.Duration.
Quand le contexte n'impose pas de type, comme avec x := Ratio, la constante prend son type par défaut :
| Catégorie de constante non typée | Type par défaut |
|---|---|
entier (42) | int |
virgule flottante (4.2) | float64 |
rune ('a') | rune (int32) |
complexe (2i) | complex128 |
| chaîne | string |
| booléen | bool |
Arithmétique exacte
Les constantes numériques non typées sont exactes. Le compilateur représente les entiers sur au moins 256 bits, donc les valeurs intermédiaires peuvent dépasser de loin n'importe quel type Go :
Huge lui-même ne peut pas être affiché comme entier, parce que le passer à fmt.Println le convertit en int, et le compilateur le détecte (float64(Huge) fonctionne, puisqu'un flottant peut contenir cet ordre de grandeur) :
cannot use Huge (untyped int constant 1267650600228229401496703205376) as int value in argument to fmt.Println (overflows)
La même vérification bloque de plus petites erreurs à la compilation, comme var b byte = 300 :
cannot use 300 (untyped int constant) as byte value in variable declaration (overflows)
Constantes typées
Donnez un type à une constante et elle se comporte partout comme une valeur de ce type, y compris le refus de Go de mélanger les types :
const Limit int = 10
var f float64 = 2
fmt.Println(Limit * f)
invalid operation: Limit * f (mismatched types int and float64)
Avec const Limit = 10 (non typée), Limit * f compile et donne 20. Laissez donc les constantes non typées, sauf si le type a un sens. C'est le cas quand vous déclarez des constantes de votre propre type nommé, ce qui est la façon dont Go construit les enums :
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
)
Ici le type est tout l'intérêt : une fonction qui prend un Weekday documente ce qu'elle attend. iota et les motifs d'enum construits dessus sont traités sur la page enums et iota.
const ou var
const | var | |
|---|---|---|
| Peut changer | non | oui |
| Valeur connue | à la compilation | à l'exécution |
| Types autorisés | bool, numériques, string | tous |
| Occupe de la mémoire à l'exécution | non | oui |
On peut prendre son adresse (&x) | non | oui |
| Inutilisée, c'est une erreur | non | oui, pour les locales |
Utilisez const pour tout ce qui est réellement fixe : limites, tailles, noms, codes de protocole, chaînes de format. Vous obtenez gratuitement la vérification des dépassements à la compilation et une arithmétique exacte.
Pièges
Les constantes typées ne s'adaptent pas. const Timeout int = 5 ne peut pas être passée là où un time.Duration est attendu sans conversion ; une constante non typée const Timeout = 5 peut être multipliée : Timeout * time.Second.
La division entière s'applique aux constantes entières. const Half = 1 / 2 vaut 0, parce que les deux opérandes sont des entiers non typés. Écrivez 1.0 / 2 pour obtenir 0.5.
Pas d'adresse. &MaxRetries ne compile pas. Si une API veut un *int, copiez d'abord la constante dans une variable.
Questions fréquentes
Comment déclarer une constante en Go ?
Avec const : const MaxRetries = 3 ou, avec un type explicite, const Timeout time.Duration = 5 * time.Second. Regroupez-en plusieurs dans un bloc : const ( A = 1; B = 2 ). La valeur doit pouvoir être calculée à la compilation.
Peut-on créer une slice, une map ou un tableau const en Go ?
Non. Les constantes ne peuvent être que des booléens, des nombres (runes comprises) et des chaînes. const Colors = []string{"red"} échoue avec is not constant. Utilisez une var au niveau du package, et si les appelants ne doivent pas la modifier, exposez une fonction qui renvoie une copie neuve.
Qu'est-ce qu'une constante non typée en Go ?
Une constante déclarée sans type, comme const Pi = 3.14159. Elle n'a pas de type fixe tant qu'elle n'est pas utilisée, donc la même constante fonctionne comme un float32, un float64 ou, si sa valeur le permet, un int. Les constantes non typées sont aussi exactes : le compilateur garde au moins 256 bits de précision, donc const Big = 1 << 100 est légal tant que vous ne l'utilisez que dans des expressions dont le résultat tient dans le type.
Quelle est la différence entre const et var en Go ?
Une const est fixée à la compilation et ne peut jamais changer ; elle n'occupe pas de mémoire à l'exécution et ne peut contenir qu'un bool, un nombre ou une chaîne. Une var est un emplacement mémoire qui peut être réaffecté et contenir n'importe quel type, y compris des valeurs calculées à l'exécution comme time.Now().