Menu
Coddy logo textTech

Structures génériques

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 70 sur 107.

Tout comme les fonctions, les structs peuvent également avoir des paramètres de type. Une struct générique vous permet de créer des structures de données qui fonctionnent avec n’importe quel type tout en maintenant la sécurité des types. C’est idéal pour créer des conteneurs réutilisables comme des piles, des files d’attente ou des paires clé-valeur.

Pour définir une structure générique, placez le paramètre de type après le nom de la structure :

type Box[T any] struct {
    Value T
}

func main() {
    intBox := Box[int]{Value: 42}
    strBox := Box[string]{Value: "hello"}
    
    fmt.Println(intBox.Value)  // 42
    fmt.Println(strBox.Value)  // hello
}

Contrairement aux fonctions génériques, vous devez spécifier explicitement le type lors de la création d'une instance d'une structure générique. Go ne peut pas inférer le type uniquement à partir du contexte.

Les structures génériques peuvent avoir plusieurs paramètres de type, ce qui les rend idéales pour des structures comme des paires ou des maps :

type Pair[K, V any] struct {
    Key   K
    Value V
}

p := Pair[string, int]{Key: "age", Value: 25}
fmt.Printf("%s: %d\n", p.Key, p.Value)  // age: 25

Vous pouvez également appliquer des contraintes pour garantir que les types stockés prennent en charge des opérations spécifiques :

type NumberBox[T int | float64] struct {
    Value T
}

nb := NumberBox[float64]{Value: 3.14}

Les structures génériques constituent le fondement de la création de structures de données réutilisables et de type sûr en Go. Dans la prochaine leçon, vous apprendrez comment définir des méthodes sur ces types génériques.

challenge icon

Défi

Facile

Construisons un système d’inventaire générique capable de suivre différents types d’articles ! Tu vas créer des structures conteneurs réutilisables qui fonctionnent avec n’importe quel type tout en conservant une sécurité de typage complète.

Tu organiseras ton code sur deux fichiers :

  • inventory.go : Définir tes structures conteneurs génériques.

    Crée une structure générique Item[T any] avec deux champs : Name (string) et Data (de type T). Elle représente n’importe quel article avec des données associées d’un type flexible.

    Crée une structure générique Container[T any] avec un seul champ Items qui contient une tranche de Item[T]. Ce conteneur peut stocker plusieurs articles du même type de données.

    Crée une structure générique contrainte PricedItem[T int | float64] avec trois champs : Name (string), Quantity (int) et Price (de type T). La contrainte garantit que les prix sont toujours numériques.

    Implémente une fonction NewContainer[T any]() *Container[T] qui crée et renvoie un pointeur vers un Container vide.

    Implémente une méthode Add sur *Container[T] qui prend un nom (string) et des données (T), crée un Item et l’ajoute à la tranche Items du conteneur.

    Implémente une méthode Count sur Container[T] qui renvoie le nombre d’articles dans le conteneur.

  • main.go : Montrer tes structures génériques avec différents types.

    Lis un type d’article (string, int ou priced), puis lis un nombre suivi des détails des articles.

    Pour le type string : lis des paires de nom et de données de type string. Crée un Container[string], ajoute tous les articles, puis affiche chaque article sous la forme [Name]: [Data], suivi du nombre total.

    Pour le type int : lis des paires de nom et de données entières. Crée un Container[int], ajoute tous les articles, puis affiche chaque article sous la forme [Name]: [Data], suivi du nombre total.

    Pour le type priced : lis des triplets composés du nom, de la quantité et du prix (sous forme de float). Crée directement des instances de PricedItem[float64] et affiche chaque article sous la forme [Name] x[Quantity] @ [Price], avec le prix affiché avec une décimale.

    Affiche la ligne du nombre sous la forme : Total items: [count]

Les entrées suivantes seront fournies :

  • Ligne 1 : Type d’article (string, int ou priced)
  • Ligne 2 : Nombre d’articles (entier)
  • Lignes suivantes : Détails des articles selon le type

Par exemple, avec :

string
3
Book
Fiction Novel
Pen
Blue Ink
Notebook
Lined Paper

Ta sortie doit être :

Book: Fiction Novel
Pen: Blue Ink
Notebook: Lined Paper
Total items: 3

Et avec :

int
2
Apples
50
Oranges
30

Ta sortie doit être :

Apples: 50
Oranges: 30
Total items: 2

Et avec :

priced
2
Widget
10
19.99
Gadget
5
49.50

Ta sortie doit être :

Widget x10 @ 19.9
Gadget x5 @ 49.5
Total items: 2

Remarque comment la même structure Container fonctionne parfaitement avec les chaînes et les entiers, tandis que PricedItem utilise une contrainte pour garantir que seuls les types numériques peuvent être utilisés pour les prix. Tu dois spécifier explicitement le paramètre de type lors de la création d’instances de ces structures génériques.

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Lire le type d'élément
	scanner.Scan()
	itemType := scanner.Text()
	
	// Lire le nombre
	scanner.Scan()
	count, _ := strconv.Atoi(scanner.Text())
	
	switch itemType {
	case "string":
		// TODO: Créer un Container[string] en utilisant NewContainer
		// TODO: Lire 'count' éléments (chacun a un nom sur une ligne, des données sur la ligne suivante)
		// TODO: Ajouter chaque élément au conteneur
		// TODO: Afficher chaque élément comme "[Name]: [Data]"
		// TODO: Afficher "Total items: [count]" en utilisant la méthode Count
		
	case "int":
		// TODO: Créer un Container[int] en utilisant NewContainer
		// TODO: Lire 'count' éléments (chacun a un nom sur une ligne, des données entières sur la ligne suivante)
		// TODO: Ajouter chaque élément au conteneur
		// TODO: Afficher chaque élément comme "[Name]: [Data]"
		// TODO: Afficher "Total items: [count]" en utilisant la méthode Count
		
	case "priced":
		// TODO: Créer une slice pour contenir des instances de PricedItem[float64]
		// TODO: Lire 'count' éléments (chacun a un nom, une quantité et un prix sur des lignes séparées)
		// TODO: Créer un PricedItem[float64] pour chacun et l'ajouter à la slice
		// TODO: Afficher chaque élément comme "[Name] x[Quantity] @ [Price]" avec le prix affichant une décimale
		// TODO: Afficher "Total items: [count]"
	}
	
	_ = scanner // Utiliser scanner pour lire l'entrée
	_ = count   // Utiliser count pour la boucle
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur Go en ligne