Generics en Go : guide complet sur les génériques

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

Generics en Go : pourquoi en avez-vous besoin et comment les utiliser

Avec la sortie de Go 1.18, l'une des fonctionnalités les plus attendues est apparue dans le langage : les generics (programmation générique). Jusqu'à présent, les développeurs devaient soit dupliquer le code pour différents types de données, soit utiliser l'interface vide interface{} avec un cast de type ultérieur. Les generics résolvent ce problème de manière radicale. Dans cet article, nous verrons pourquoi ils sont nécessaires, comment les utiliser en pratique et quels pièges vous attendent.

Que sont les generics et pourquoi en avez-vous besoin en Go ?

Les generics (ou types génériques) permettent d'écrire des fonctions, des structures et des méthodes qui fonctionnent avec n'importe quel type de données, tout en conservant un typage strict. Cela signifie que vous pouvez écrire une seule fonction qui fonctionnera à la fois avec des nombres, des chaînes de caractères et des types personnalisés, sans perdre l'information sur le type au moment de la compilation.

Avant l'apparition des generics, les développeurs Go utilisaient deux approches principales :

  • Duplication de code — écrire des fonctions séparées pour int, string, float64, etc.
  • Interface vide — utiliser interface{} avec une assertion de type ou de la réflexion, ce qui était dangereux et lent.

Les generics résolvent ces problèmes en permettant d'écrire du code universel, mais typé de manière sécurisée. Le compilateur vérifie les types au moment de la compilation, ce qui élimine les erreurs d'exécution.

Syntaxe des Generics : paramètres de type

L'idée principale des generics en Go est celle des paramètres de type (type parameters). Ils sont déclarés entre crochets après le nom de la fonction ou du type.

Considérons un exemple très simple — une fonction qui retourne la valeur minimale de deux valeurs :

package main

import "fmt"

// Fonction générique avec un paramètre de type T
func Min[T comparable](a, b T) T {
    if a < b {
        return a
    }
    return b
}

func main() {
    fmt.Println(Min[int](10, 20))       // 10
    fmt.Println(Min[string]("a", "b"))  // "a"
    fmt.Println(Min(3.14, 2.71))        // 2.71 (le type est déduit automatiquement)
}

Ici, T est un paramètre de type. comparable est une contrainte (constraint) qui indique que le type T doit prendre en charge les opérateurs de comparaison. Sans cette contrainte, le compilateur n'autoriserait pas l'utilisation de <.

Important : Go peut déduire automatiquement les paramètres de type à partir des arguments, donc dans la plupart des cas, vous n'avez pas besoin de les spécifier explicitement.

Contraintes (Constraints) dans les generics Go

Les contraintes sont un élément clé des generics. Elles définissent quelles opérations sont autorisées pour les paramètres de type. Sans contraintes, le compilateur ne sait pas quelles méthodes ou opérateurs peuvent être appliqués à T.

Go dispose de plusieurs contraintes intégrées :

  • any — synonyme de interface{}, autorise n'importe quel type.
  • comparable — autorise les types qui prennent en charge == et !=.
  • constraints.Ordered — du paquet golang.org/x/exp/constraints, autorise tous les types ordonnés (nombres et chaînes de caractères).

Vous pouvez également créer vos propres contraintes à l'aide d'interfaces :

package main

import "fmt"

// Contrainte personnalisée : le type doit avoir une méthode String()
type Stringer interface {
    String() string
}

// Fonction fonctionnant avec n'importe quel Stringer
func Print[T Stringer](value T) {
    fmt.Println(value.String())
}

type User struct {
    Name string
}

func (u User) String() string {
    return "User: " + u.Name
}

func main() {
    user := User{Name: "Alice"}
    Print(user) // User: Alice
}

Notez : dans Go 1.18+, les interfaces peuvent être utilisées comme contraintes, et elles peuvent contenir non seulement des méthodes, mais aussi des types concrets.

Blogs

Book Recommendations