Go (Golang) compte 25 mots-clés : break, case, chan, const, continue, default, defer, else, fallthrough, for, func, go, goto, if, import, interface, map, package, range, return, select, struct, switch, type et var. Ils sont réservés : vous ne pouvez donc pas les utiliser comme noms de variables, de fonctions ou de types. La liste n'a pas changé depuis Go 1.0 en 2012, et Go 1.27 a toujours les mêmes 25 (spécification Go). Python compte 35 mots-clés, Java 51 et C++ plus de 80. Cette liste courte est voulue. Go a été conçu pour être assez petit pour que vous puissiez garder tout le langage en tête.
En bref
- Go a exactement 25 mots-clés. La liste figure dans la spécification Go et n'a pas bougé depuis Go 1.0.
- Ils se répartissent en quatre groupes. Les déclarations (
package,import,const,var,type,func), les types composites (struct,interface,map,chan), le contrôle de flux (12 mots-clés, deifàreturn) et la concurrence et le nettoyage (go,select,defer). - Il n'existe qu'un seul mot-clé de boucle.
forcouvre les boucles avec compteur, les boucles « while », les boucles infinies et, avecrange, l'itération sur les slices, les maps, les channels, les entiers et les fonctions itératrices. any,int,string,error,nil,true,lenetmakene sont pas des mots-clés. Ce sont des identifiants prédéclarés. Vous pouvez donc les masquer, même si, en général, il vaut mieux s'en abstenir.- Les generics n'ont ajouté aucun mot-clé. Go 1.18 a introduit les paramètres de type avec des noms prédéclarés (
any,comparable) plutôt qu'avec de nouveaux mots réservés.
La liste complète des mots-clés Go
| Mot-clé | Catégorie | Rôle |
|---|---|---|
package | Déclaration | Nomme le package auquel appartient un fichier |
import | Déclaration | Importe d'autres packages |
const | Déclaration | Déclare une constante connue à la compilation |
var | Déclaration | Déclare une variable |
type | Déclaration | Déclare un type nommé ou un alias |
func | Déclaration | Déclare une fonction, une méthode ou un littéral de fonction |
struct | Type composite | Regroupe des champs nommés dans un seul type |
interface | Type composite | Déclare un ensemble de méthodes (ou une contrainte de type) |
map | Type composite | Déclare un type de table de hachage |
chan | Type composite | Déclare un type de channel |
if | Contrôle de flux | Exécute un bloc quand une condition est vraie |
else | Contrôle de flux | Exécute un bloc quand la condition du if est fausse |
for | Contrôle de flux | La seule boucle de Go |
range | Contrôle de flux | Itère sur les slices, maps, chaînes, channels, entiers et itérateurs |
switch | Contrôle de flux | Choisit une branche parmi plusieurs |
case | Contrôle de flux | Une branche d'un switch ou d'un select |
default | Contrôle de flux | La branche exécutée quand aucun case ne correspond |
fallthrough | Contrôle de flux | Poursuit dans le case suivant d'un switch |
break | Contrôle de flux | Sort d'un for, d'un switch ou d'un select |
continue | Contrôle de flux | Passe à l'itération suivante de la boucle |
goto | Contrôle de flux | Saute vers un label dans la même fonction |
return | Contrôle de flux | Sort d'une fonction, avec ou sans valeurs |
go | Concurrence | Lance une fonction dans une nouvelle goroutine |
select | Concurrence | Attend sur plusieurs opérations de channel |
defer | Nettoyage | Exécute un appel au retour de la fonction |
Quels sont les mots-clés de déclaration en Go ?
Go possède six mots-clés de déclaration, et ce petit chargeur de configuration les utilise tous :
example.gogopackage main import ( "fmt" "time" ) const defaultTimeout = 5 * time.Second var maxRetries = 3 type Config struct { Addr string Timeout time.Duration } func newConfig(addr string) Config { return Config{Addr: addr, Timeout: defaultTimeout} } func main() { cfg := newConfig(":8080") fmt.Println(cfg.Addr, cfg.Timeout, maxRetries) }
package
Chaque fichier Go commence par une clause package. Tous les fichiers d'un même répertoire partagent le même nom de package. Le package nommé main est particulier : il produit un exécutable, et sa fonction main est le point d'entrée du programme. Tout autre nom produit une bibliothèque que d'autres packages importent. Le mot-clé package en Go détaille les règles de nommage, la visibilité et les packages _test.
import
import rend accessibles dans le fichier les noms exportés d'un autre package, comme fmt.Println ou http.ListenAndServe. Vous pouvez regrouper les imports entre parenthèses, en renommer un (yaml "gopkg.in/yaml.v3") ou importer un package uniquement pour ses effets de bord avec _. Go refuse de compiler un fichier qui contient un import inutilisé, si bien qu'un fichier ne liste jamais un package dont il ne se sert pas. Le mot-clé import en Go détaille les alias, les imports blank et dot, ainsi que les cycles d'import.
const
const déclare une valeur fixée à la compilation, comme un timeout ou un nom d'en-tête. Les constantes peuvent être non typées. const maxBodyBytes = 1 << 20 n'a pas de type tant que vous ne l'utilisez pas, elle fonctionne donc comme un int ou un int64 sans conversion. Dans un bloc const, l'identifiant prédéclaré iota compte à partir de 0, et c'est ainsi que Go écrit les énumérations. Le mot-clé const en Go détaille les constantes typées et non typées, iota et les énumérations.
var
var déclare une variable avec un type explicite, une valeur initiale ou les deux. Toute variable démarre à la valeur zéro de son type : 0, "", false ou nil. Dans les fonctions, la plupart du code Go utilise plutôt la forme courte name := value. var reste le bon choix au niveau du package et quand vous voulez délibérément la valeur zéro, comme dans var buf bytes.Buffer. Le mot-clé var en Go détaille les valeurs zéro, :=, le masquage de variables et les variables au niveau du package.
type
type déclare un nouveau type nommé, comme un struct, une interface ou une version nommée d'un type existant, par exemple type UserID int64. Le nouveau type peut avoir ses propres méthodes. Avec =, il déclare plutôt un alias (type Handler = http.Handler), qui n'est qu'un second nom pour le même type. Le mot-clé type en Go détaille les types définis, les alias, les méthodes et les types génériques.
func
func déclare les fonctions et les méthodes, et sert aussi à créer des littéraux de fonction (closures). Une méthode a un receveur avant son nom : func (s *Server) Start() error. Les fonctions Go peuvent renvoyer plusieurs valeurs, et c'est ainsi que les erreurs sont remontées : func parse(body []byte) (Request, error). Le mot-clé func en Go détaille les méthodes, les closures, les fonctions variadiques et les options fonctionnelles.
Quels mots-clés Go construisent des types composites ?
Quatre mots-clés construisent des types à partir d'autres types. Les tableaux, les slices et les pointeurs sont aussi des types composites, mais ils utilisent des symboles ([N]T, []T, *T) au lieu de mots-clés.
example.gogotype Notifier interface { Notify(ctx context.Context, msg string) error } type SlackNotifier struct { Channel string } func (s SlackNotifier) Notify(ctx context.Context, msg string) error { fmt.Printf("#%s: %s\n", s.Channel, msg) return nil } func main() { var n Notifier = SlackNotifier{Channel: "alerts"} statusCounts := map[int]int{200: 41, 500: 2} events := make(chan string, 10) events <- fmt.Sprintf("%d server errors", statusCounts[500]) n.Notify(context.Background(), <-events) }
struct
struct regroupe des champs nommés dans un seul type. C'est ce qui remplace les classes en Go : vous attachez des méthodes à un type struct, et vous réutilisez du comportement en incorporant un struct dans un autre plutôt qu'en héritant. Les tags de struct comme json:"email" indiquent à des packages tels que encoding/json comment encoder chaque champ. Le mot-clé struct en Go détaille les tags de struct, les receveurs valeur et pointeur, l'incorporation ainsi que la comparaison et la copie de structs.
interface
interface déclare un ensemble de méthodes. Un type satisfait une interface du simple fait qu'il possède ces méthodes, sans déclaration implements : SlackNotifier ci-dessus est donc un Notifier sans avoir à le dire. Depuis Go 1.18, les interfaces décrivent aussi des contraintes de type pour les generics, comme interface{ ~int | ~float64 }. Le mot-clé interface en Go détaille la satisfaction implicite, les interfaces nil, les assertions de type et les contraintes.
map
map déclare un type de table de hachage, écrit map[KeyType]ValueType. Vous en créez une avec un littéral ou avec make, et une map nil provoque un panic à l'écriture. La lecture d'une clé absente renvoie la valeur zéro, et la forme à deux valeurs count, ok := statusCounts[404] vous indique si la clé était présente. La spécification ne définit pas l'ordre d'itération, et le runtime le rend aléatoire exprès. var vs make en Go explique pourquoi une map nil provoque un panic à l'écriture alors qu'une slice nil non. Le mot-clé map en Go détaille l'idiome comma-ok, l'ordre d'itération, les ensembles, l'accès concurrent et le package maps.
chan
chan déclare un type de channel, le tuyau par lequel les goroutines se transmettent des valeurs. chan<- Job est en envoi seul et <-chan Job en réception seule, ce qui permet à une signature de fonction d'indiquer le sens qu'elle utilise. Les channels se créent avec make, et un channel bufferisé (make(chan string, 10)) conserve les valeurs jusqu'à ce que quelqu'un les reçoive. Le mot-clé chan en Go détaille les channels bufferisés et non bufferisés, la fermeture, les deadlocks et les patterns avec select.
Quels mots-clés Go contrôlent le flux d'un programme ?
Douze mots-clés gèrent les branchements et les boucles. Go se passe de while, do, try, catch et de l'opérateur ternaire. Les erreurs sont des valeurs de retour ordinaires que vous vérifiez avec if.
example.gogofunc parse(body []byte) (Request, error) { var req Request if err := json.Unmarshal(body, &req); err != nil { return Request{}, fmt.Errorf("decode request: %w", err) } if req.Email == "" { return Request{}, errors.New("email is required") } return req, nil } func countErrors(lines []string) int { errs := 0 for _, line := range lines { if strings.HasPrefix(line, "#") { continue } if line == "EOF" { break } if strings.Contains(line, "level=error") { errs++ } } return errs }
if
if exécute un bloc quand une condition est vraie. La condition n'a pas besoin de parenthèses, mais les accolades sont obligatoires. Un if peut commencer par une instruction courte, et la variable qu'elle déclare n'existe que dans le if et ses branches else. Le code Go utilise cette forme en permanence, comme dans if err := json.Unmarshal(body, &req); err != nil. Le mot-clé if en Go détaille les conditions strictement booléennes, les instructions d'initialisation, le masquage, les retours anticipés et l'absence d'opérateur ternaire.
else
else s'exécute quand la condition du if est fausse, et else if enchaîne d'autres conditions. Le Go idiomatique utilise else moins souvent que la plupart des langages. Quand la branche if se termine par return, la suite de la fonction constitue déjà le cas « sinon ». Le code Go garde donc le chemin nominal sans indentation et retourne tôt en cas d'erreur. Le mot-clé else en Go détaille les chaînes else if, la portée des variables déclarées dans le if, les retours anticipés et l'absence d'opérateur ternaire.
for
for est le seul mot-clé de boucle de Go. for i := 0; i < n; i++ est la boucle classique avec compteur, for queue.Len() > 0 est une boucle « while » et for { ... } boucle indéfiniment jusqu'à ce que quelque chose en sorte. Depuis Go 1.22, dans les modules dont le go.mod déclare go 1.22 ou plus, chaque itération reçoit sa propre copie de la variable de boucle : les closures et les goroutines lancées dans une boucle ne partagent donc plus une seule et même variable. Le mot-clé for en Go détaille les trois formes de boucle, range, les variables de boucle de Go 1.22, les labels et les erreurs de boucle courantes.
range
range fait itérer une boucle for sur une collection. Il vous donne l'index et la valeur pour les slices et les tableaux, la clé et la valeur pour les maps, l'offset en octets et la rune pour les chaînes, et les valeurs reçues pour les channels. Go 1.22 a ajouté l'itération sur un entier (for attempt := range 3 s'exécute avec 0, 1 et 2), et Go 1.23 l'itération sur les fonctions itératrices, comme celle que renvoie maps.Keys(m).
switch
switch choisit une branche parmi plusieurs. Contrairement à C et Java, un switch Go s'arrête après le cas correspondant : vous n'avez jamais besoin d'un break à la fin de chaque cas. Un switch sans expression fonctionne comme une chaîne if/else if plus lisible, et un type switch (switch v := x.(type)) aiguille selon le type dynamique d'une valeur d'interface.
case
case marque une branche d'un switch ou d'un select. Un même cas peut lister plusieurs valeurs : case "GET", "HEAD":. Dans un switch, les cas sont évalués de haut en bas, et la première correspondance l'emporte.
default
default est la branche exécutée quand aucun case ne correspond. Elle peut apparaître n'importe où dans le switch, même si la convention la place en dernier. Dans un select, un cas default rend toute l'instruction non bloquante : si aucun channel n'est prêt, default s'exécute immédiatement.
fallthrough
fallthrough fait continuer un switch dans le corps du cas suivant sans vérifier la condition de ce cas. Il est rare dans du code réel, et c'est le seul endroit où un switch Go se comporte comme en C. Les permissions hiérarchisées sont un cas où il se lit bien :
example.gogofunc permissions(role string) []string { var perms []string switch role { case "admin": perms = append(perms, "delete") fallthrough case "editor": perms = append(perms, "write") fallthrough case "viewer": perms = append(perms, "read") default: return nil } return perms }
permissions("editor") renvoie [write read] et permissions("admin") renvoie [delete write read]. fallthrough doit être la dernière instruction d'un cas, et il est interdit dans un type switch.
break
break sort du for, du switch ou du select le plus interne. Ce dernier point est un piège courant : un break dans un select ne quitte que le select, pas la boucle qui l'entoure. Pour sortir de la boucle, posez-lui un label et écrivez break loop :
example.gogofunc drain(ctx context.Context, events <-chan string) { loop: for { select { case ev, ok := <-events: if !ok { break loop } fmt.Println("event:", ev) case <-ctx.Done(): break loop } } fmt.Println("drained") }
continue
continue saute le reste de l'itération en cours et démarre la suivante. Dans countErrors ci-dessus, il ignore les lignes de commentaire. Comme break, il accepte un label pour passer à l'itération suivante d'une boucle externe depuis une boucle imbriquée.
goto
goto saute vers un label dans la même fonction. Il ne peut ni sauter à l'intérieur d'un bloc ni passer par-dessus une déclaration de variable, ce qui écarte la plupart des problèmes que pose goto en C. Vous l'écrirez rarement. On le trouve surtout dans du code généré et dans quelques parties bas niveau de la bibliothèque standard. Le backend de LevelUpGo compte environ 30 000 lignes de Go hors tests et données de seed. Il n'utilise goto et fallthrough aucune fois, contre plus de 250 boucles range et plus de 40 appels defer.
return
return termine une fonction et renvoie ses résultats. Les fonctions Go renvoient souvent deux valeurs, un résultat et une error, et l'appelant vérifie l'erreur immédiatement. Avec des paramètres de résultat nommés, un return nu renvoie leurs valeurs courantes, mais la plupart des guides de style le réservent aux fonctions courtes.
Quels mots-clés Go gèrent la concurrence et le nettoyage ?
Les trois derniers mots-clés sont go, select et defer. Avec chan, ce sont eux qu'un serveur Go utilise pour exécuter du travail en parallèle puis faire le ménage.
example.gogofunc startWorkers(ctx context.Context, n int, jobs <-chan string, results chan<- []byte) { for range n { go worker(ctx, jobs, results) } } func worker(ctx context.Context, jobs <-chan string, results chan<- []byte) { for { select { case url, ok := <-jobs: if !ok { return } body, err := fetch(ctx, url) if err != nil { log.Printf("fetch %s: %v", url, err) continue } results <- body case <-ctx.Done(): return } } } func fetch(ctx context.Context, url string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, 2*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) }
go
go lance un appel de fonction dans une nouvelle goroutine et continue sans l'attendre. startWorkers ci-dessus exécute go worker(ctx, jobs, results) dans une boucle, ce qui vous donne un pool de workers. Les goroutines démarrent avec une pile de quelques kilo-octets, si bien qu'un serveur peut en faire tourner des centaines de milliers. L'instruction go ignore les valeurs de retour de la fonction : les résultats reviennent donc par des channels, et un sync.WaitGroup ou un errgroup attend la fin du travail.
select
select attend sur plusieurs opérations de channel et exécute la première qui est prête. Si plusieurs sont prêtes en même temps, il en choisit une au hasard. Le worker ci-dessus s'en sert pour prendre la tâche suivante ou s'arrêter quand le context est annulé. Associer un channel à ctx.Done() ou à time.After, c'est ainsi que le code Go ajoute timeouts et annulation à tout ce qui bloque.
defer
defer programme un appel qui s'exécutera au retour de la fonction englobante, que celle-ci retourne normalement ou panique. Le nettoyage reste ainsi à côté du code qui en a besoin : defer resp.Body.Close(), defer mu.Unlock(), defer cancel(). Les appels différés s'exécutent dans l'ordre dernier entré, premier sorti, et leurs arguments sont évalués quand la ligne defer s'exécute, pas à la fin. Un defer placé dans une boucle ne s'exécute qu'au retour de la fonction entière, ce qui fait partie des erreurs Go courantes à connaître tôt.
Qu'est-ce qui n'est pas un mot-clé en Go ?
Beaucoup de noms qui semblent intégrés au langage sont des identifiants prédéclarés, pas des mots-clés. La spécification Go les liste dans le bloc universel, qui englobe chaque package (spécification Go) :
| Catégorie | Identifiants prédéclarés |
|---|---|
| Types | any, bool, byte, comparable, complex64, complex128, error, float32, float64, int, int8, int16, int32, int64, rune, string, uint, uint8, uint16, uint32, uint64, uintptr |
| Constantes | true, false, iota |
| Valeur zéro | nil |
| Fonctions | append, cap, clear, close, complex, copy, delete, imag, len, make, max, min, new, panic, print, println, real, recover |
La différence compte, car les identifiants prédéclarés peuvent être redéclarés dans une portée interne. Ce code compile :
example.gogofunc logAddrChange(cur, next Config) { old, new := cur.Addr, next.Addr if old != new { log.Printf("addr changed from %s to %s", old, new) } } func countLines(lines []string) int { len := len(lines) return len }
Nommer une variable new est courant dans du code qui compare anciennes et nouvelles valeurs, et cela fonctionne. En revanche, après len := len(lines), tout appel ultérieur à len(...) dans cette fonction échoue avec invalid operation: cannot call len (variable of type int): int is not a function. Un mot-clé, lui, ne peut pas du tout être utilisé ainsi. var := 3 échoue avec syntax error: unexpected :=, expected name. Des linters comme predeclared dans golangci-lint signalent les built-ins masqués, car un code comme countLines compile mais déroute le lecteur suivant.
Garder ces noms hors de la liste des mots-clés permet à Go d'évoluer sans casser les programmes existants. any (Go 1.18) ainsi que min, max et clear (Go 1.21) ont été ajoutés comme identifiants prédéclarés, si bien que tout code qui utilisait déjà ces noms comme variables a continué de compiler.
La place de LevelUpGo
LevelUpGo enseigne Go au moyen d'exercices qui exécutent du vrai code Go dans le navigateur. Le cours Go Basics couvre les mots-clés de déclaration et de contrôle de flux, de var et const à switch et for. Concurrency Fundamentals couvre go, chan, select et defer, et Simplification montre quand un switch se lit mieux qu'une chaîne de if. Le Training Ground propose de courts exercices indépendants pour les pratiquer en dehors d'un cours.
Questions fréquentes
Combien de mots-clés le langage Go compte-t-il ?
Go compte 25 mots-clés : break, case, chan, const, continue, default, defer, else, fallthrough, for, func, go, goto, if, import, interface, map, package, range, return, select, struct, switch, type et var. La liste est définie dans la spécification Go et n'a pas changé depuis Go 1.0.
any est-il un mot-clé en Go ?
Non. any est un identifiant prédéclaré, un alias de interface{} ajouté dans Go 1.18. Il en va de même pour int, string, error, nil, true, false, iota et les fonctions intégrées comme len, make et append. Vous pouvez les redéclarer dans une portée interne, même si les linters vous avertissent quand vous le faites.
Peut-on utiliser un mot-clé Go comme nom de variable ?
Non. Les mots-clés sont réservés : var := 3 ou func type() provoque une erreur de syntaxe. La solution habituelle est une variante courte. Le code Go utilise souvent typ ou kind au lieu de type, pkg au lieu de package et fn au lieu de func.
Go a-t-il ajouté des mots-clés depuis Go 1.0 ?
Non. Les 25 mots-clés de Go 1.27 sont les 25 mêmes que ceux livrés avec Go 1.0 en mars 2012. Les generics, range sur les entiers, les fonctions itératrices et les méthodes génériques de Go 1.27 sont tous arrivés sans nouveau mot-clé. La promesse de compatibilité de Go 1 rend de nouveaux mots-clés peu probables, car un nouveau mot réservé casserait tous les programmes qui l'utilisent déjà comme nom.
Pourquoi Go a-t-il si peu de mots-clés ?
Ses concepteurs l'ont voulu ainsi. La FAQ de Go indique qu'ils ont « essayé de réduire l'encombrement et la complexité » et que la « syntaxe est épurée et utilise peu de mots-clés ». C'est pourquoi Go a un seul mot-clé de boucle au lieu de trois, et pourquoi les erreurs sont des valeurs de retour plutôt qu'un try/catch. Le résultat est un langage que l'on apprend vite, et le code Go se lit à peu près de la même façon d'une base de code à l'autre.
Sources
- The Go Programming Language Specification, Keywords : https://go.dev/ref/spec#Keywords
- The Go Programming Language Specification, Predeclared identifiers : https://go.dev/ref/spec#Predeclared_identifiers
- Go 1 and the Future of Go Programs (promesse de compatibilité) : https://go.dev/doc/go1compat
- Go FAQ, « What are the guiding principles in the design? » : https://go.dev/doc/faq#principles
- Notes de version de Go 1.22 (variables de boucle, range sur les entiers) : https://go.dev/doc/go1.22
- Notes de version de Go 1.23 (range sur les fonctions itératrices) : https://go.dev/doc/go1.23
- Python language reference, Keywords : https://docs.python.org/3/reference/lexical_analysis.html#keywords
- Java Language Specification (Java SE 21), Keywords : https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.9
- cppreference, C++ keywords : https://en.cppreference.com/w/cpp/keyword
