Go en 2025 : un langage au seuil d'une révolution
\n\nQuand en 2009 Rob Pike, Ken Thompson et Robert Griesemer ont publié Go, peu de gens imaginaient que 16 ans plus tard, ce langage deviendrait la base de Kubernetes, Docker, Prometheus et de milliers d'autres projets. Mais 2025 n'est pas une simple étape d'évolution. C'est l'année où Go cesse d'être un « langage simple pour le backend » pour se transformer en plateforme pour l'IA, de nouveaux standards de gestion d'erreurs et un travail natif avec les itérateurs.
\n\nDans cet article, nous analyserons les changements clés déjà annoncés ou attendus dans Go 1.24–1.25, et nous les illustrerons avec des exemples de code concrets. Si vous suivez l'évolution du langage, vous êtes sur la bonne voie.
\n\n1. Les génériques deviennent adultes (Go 1.24)
\n\nLes génériques sont apparus dans Go en version 1.18, mais de nombreux développeurs se plaignaient de limitations : impossible d'utiliser des types génériques dans les méthodes, et une syntaxe trop lourde. En 2025, la situation change radicalement.
\n\nNouvelles possibilités : types génériques dans les méthodes
\n\nAuparavant, pour écrire une fonction fonctionnant avec n'importe quelle slice, il fallait créer une fonction séparée, et non une méthode. Désormais, cette limitation est levée :
\n\npackage main\n\nimport "fmt"\n\n// Nouvelle syntaxe : méthode avec générique\ntype Stack[T any] struct {\n items []T\n}\n\nfunc (s *Stack[T]) Push(item T) {\n s.items = append(s.items, item)\n}\n\nfunc (s *Stack[T]) Pop() (T, bool) {\n if len(s.items) == 0 {\n var zero T\n return zero, false\n }\n item := s.items[len(s.items)-1]\n s.items = s.items[:len(s.items)-1]\n return item, true\n}\n\nfunc main() {\n stack := Stack[int]{}\n stack.Push(10)\n stack.Push(20)\n val, ok := stack.Pop()\n fmt.Println(val, ok) // 20 true\n}\n\nCela simplifie la création de structures de données génériques et rend le code plus propre. Fini les bricolages avec les interfaces.
\n\n2. Révolution dans la gestion des erreurs : try et contextes intégrés
\n\nLa gestion des erreurs en Go a toujours été un sujet de débat. La construction if err != nil est puissante, mais fastidieuse. En 2025, la communauté obtient enfin une alternative.
Syntaxe try envisagée
\n\nBien que la syntaxe exacte soit encore en discussion, Go 1.25 devrait introduire le mot-clé try, qui réduira le code passe-partout :
package main\n\nimport (\n "fmt"\n "os"\n)\n\nfunc readConfig() (string, error) {\n data, err := os.ReadFile("config.yaml")\n if err != nil {\n return "", err\n }\n return string(data), nil\n}\n\n// Nouvelle version avec try (syntaxe envisagée)\nfunc readConfigV2() (string, error) {\n data := try os.ReadFile("config.yaml")\n return string(data), nil\n}\n\nfunc main() {\n cfg, err := readConfigV2()\n if err != nil {\n fmt.Println("Erreur :", err)\n return\n }\n fmt.Println("Configuration :", cfg)\n}\n\nCela ne remplace pas l'ancienne approche, mais offre un choix. Pour les cas simples — try, pour une logique complexe — le classique if err.
3. Itérateurs et for-range de nouvelle génération
\n\nGo a toujours été conservateur concernant les boucles. Mais avec la popularité croissante de la programmation fonctionnelle, le langage introduit des itérateurs natifs. Cela permet d'écrire un code plus expressif sans perte de performance.
\n\nExemple : itérateur pour un arbre
\n\npackage main\n\nimport "fmt"\n\ntype TreeNode struct {\n Value int\n Left *TreeNode\n Right *TreeNode\n}\n\n// Itérateur pour le parcours en profondeur (in-order)\nfunc (n *TreeNode) Iter() func() (int, bool) {\n stack := []*TreeNode{}\n current := n\n\n return func() (int, bool) {\n for current != nil || len(stack) > 0 {\n if current != nil {\n stack = append(stack, current)\n current = current.Left\n } else {\n node := stack[len(stack)-1]\n stack = stack[:len(stack)-1]\n val :=