Les génériques en Go : comment la programmation générique change la donne

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Tout a commencé avec Go 1.18 : pourquoi les génériques ne sont pas qu'une simple fonctionnalité à la mode ?

\n\n

Pendant longtemps, la communauté Go s'est vantée de la simplicité du langage. L'absence de programmation générique (generics) était considérée comme un choix délibéré : « nous n'avons pas besoin de modèles complexes, nous écrivons du code compréhensible ». Mais la réalité a rattrapé son retard. Les développeurs en ont eu assez de copier-coller des fonctions pour int, string et float64 — ou d'utiliser interface{} avec un transtypage ultérieur, perdant ainsi la sécurité à la compilation.

\n\n

La sortie de Go 1.18 (2022) a été une révolution. Les génériques (generics) ont ajouté au langage des paramètres de type (type parameters) et des contraintes (constraints). Désormais, les programmeurs Go peuvent écrire des structures de données et des algorithmes génériques sans sacrifier les performances et le typage strict.

\n\n

Dans cet article sur pythonlib.ru, nous allons comprendre comment fonctionnent les generics en Go, voir des exemples de code concrets et comprendre quand les utiliser, et quand ne pas le faire. C'est parti !

\n\n

Que sont les generics en Go en termes simples ?

\n\n

Imaginez que vous écrivez une fonction qui trouve l'élément minimum dans une slice. Sans génériques, vous devriez créer trois versions : pour int, float64 et string. Ou utiliser interface{} avec un transtypage — lent et dangereux.

\n\n

Les generics permettent d'écrire une seule fonction qui fonctionne avec n'importe quel type satisfaisant certaines conditions. La syntaxe est simple : après le nom de la fonction, entre crochets, on indique les paramètres de type.

\n\n

Syntaxe : crochets et mot-clé any

\n\n
package main\n\nimport "fmt"\n\n// Min — fonction générique pour trouver le minimum\nfunc Min[T any](a, b T) T {\n    // Erreur : l'opérateur < n'est pas défini pour any\n    // if a < b {\n    //     return a\n    // }\n    return b\n}
\n\n

Le code ci-dessus ne compilera pas, car any est une interface vide (synonyme de interface{}). Le compilateur ne sait pas si le type supporte l'opérateur <. Il faut ajouter une contrainte (constraint).

\n\n

Contraintes de types : constraints

\n\n

En Go, les contraintes sont définies via des interfaces. On peut utiliser celles intégrées du package golang.org/x/exp/constraints ou écrire les siennes.

\n\n
import (\n    "fmt"\n    "golang.org/x/exp/constraints"\n)\n\n// Min fonctionne avec tout type ordonné\nfunc Min[T constraints.Ordered](a, b T) T {\n    if a < b {\n        return a\n    }\n    return b\n}\n\nfunc main() {\n    fmt.Println(Min(10, 20))       // 10\n    fmt.Println(Min(3.14, 2.71))   // 2.71\n    fmt.Println(Min("apple", "banana")) // "apple"\n}
\n\n

Notez que constraints.Ordered inclut tous les types pour lesquels les opérateurs <, <=, >, >= sont définis — ce sont int, float, string.

\n\n

Exemples pratiques : du simple au complexe

\n\n

Voyons comment les generics en Go simplifient l'écriture de code réel.

\n\n

1. Pile générique (Stack)

\n\n

Sans génériques, il faudrait stocker []interface{} et faire des assertions de type. Avec les generics, c'est élégant et sûr.

\n\n
package main\n\nimport "fmt"\n\n// Stack — structure de données 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    intStack := Stack[int]{}\n    intStack.Push(1)\n    intStack.Push(2)\n    val, ok := intStack.Pop()\n    fmt.Println(val, ok) // 2 true\n\n    strStack := Stack[string]{}\n    strStack.Push("hello")\n                

Blogs

Book Recommendations