Generics en Go : pourquoi en a-t-on besoin et comment les utiliser pour les débutants

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

Introduction : que sont les Generics et pourquoi sont-ils apparus en Go ?

\n

Longtemps, le langage Go (Golang) est resté l'un des rares langages modernes sans support de la programmation générique (generics). Les développeurs devaient soit dupliquer le code pour différents types de données, soit utiliser des interfaces et des interface{} vides, ce qui entraînait une perte de sécurité de typage et la nécessité d'effectuer des conversions de type à l'exécution.

\n

Avec la sortie de la version Go 1.18 (février 2022), le langage a enfin introduit les generics tant attendus. Les Generics sont un mécanisme qui permet d'écrire des fonctions, des types et des structures de données fonctionnant avec des types arbitraires, tout en conservant un typage strict au moment de la compilation.

\n

Dans cet article, nous aborderons :

\n
    \n
  • Pourquoi les generics sont nécessaires en Go ;
  • \n
  • Comment déclarer des fonctions et des types génériques ;
  • \n
  • Ce que sont les constraints et comment les utiliser ;
  • \n
  • Des exemples pratiques d'application.
  • \n
\n\n

Pourquoi les Generics sont-ils nécessaires en Go ?

\n

Avant l'arrivée des generics, le problème typique était le suivant : il fallait écrire une fonction qui fonctionne avec des slices de différents types (par exemple, int, string, float64).

\n

Sans generics, il fallait soit écrire trois fonctions distinctes :

\n
func SumInts(nums []int) int {\n    total := 0\n    for _, v := range nums {\n        total += v\n    }\n    return total\n}\n\nfunc SumFloats(nums []float64) float64 {\n    total := 0.0\n    for _, v := range nums {\n        total += v\n    }\n    return total\n}\n
\n

Soit utiliser interface{} avec conversion de type — peu sûr et peu pratique.

\n

Avec les generics, une seule fonction suffit :

\n
func Sum[T int | float64](nums []T) T {\n    var total T\n    for _, v := range nums {\n        total += v\n    }\n    return total\n}\n
\n

Les avantages sont évidents :

\n
    \n
  • Sécurité de typage — les erreurs de type sont détectées à la compilation ;
  • \n
  • Réduction de la duplication de code — une fonction pour plusieurs types ;
  • \n
  • Lisibilité — le code devient plus concis et compréhensible.
  • \n
\n\n

Bases de la syntaxe des Generics en Go

\n

Déclaration d'une fonction générique

\n

La syntaxe de base utilise les crochets [] pour indiquer les paramètres de type :

\n
func NomFonction[NomType constraint](paramètres) résultat {\n    // corps de la fonction\n}\n
\n

Exemple d'une fonction simple qui retourne la valeur passée :

\n
func Identity[T any](value T) T {\n    return value\n}\n\nfunc main() {\n    fmt.Println(Identity[int](42))       // 42\n    fmt.Println(Identity[string]("Go"))  // Go\n}\n
\n

Go peut déduire automatiquement le type, donc la spécification explicite [int] n'est pas obligatoire :

\n
fmt.Println(Identity(42))       // Go comprend que T = int\nfmt.Println(Identity("Go"))    // T = string\n
\n\n

Types génériques (structures)

\n

Les generics fonctionnent non seulement avec les fonctions, mais aussi avec les types personnalisés :

\n
type Stack[T any] struct {\n    elements []T\n}\n\nfunc (s *Stack[T]) Push(value T) {\n    s.elements = append(s.elements, value)\n}\n\nfunc (s *Stack[T]) Pop() (T, bool) {\n    if len(s.elements) == 0 {\n        var zero T\n        return zero, false\n    }\n    value := s.elements[len(s.elements)-1]\n    s.elements = s.elements[:len(s.elements)-1]\n    return value, true\n}\n\nfunc main() {\n    intStack := Stack[int]{}\n    intStack.Push(10)\n    intStack.Push(20)\n    val, ok := intStack.Pop()\n    fmt.Println(val, ok) // 20 true\n}\n
\n\n

Constraints : restrictions pour les types

\n

Dans les exemples ci-dessus, nous avons utilisé any — une constraint intégrée signifiant "n'importe quel type". Cependant, il est souvent nécessaire d'imposer des restrictions : par exemple, que le type supporte la comparaison ou les opérations arithmétiques.

\n

Intégrées

Blogs

Book Recommendations