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: 25Vous 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.
Défi
FacileConstruisons 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) etData(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 champItemsqui contient une tranche deItem[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) etPrice(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
Addsur*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
CountsurContainer[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,intoupriced), 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 unContainer[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 unContainer[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 dePricedItem[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,intoupriced) - 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 PaperTa sortie doit être :
Book: Fiction Novel
Pen: Blue Ink
Notebook: Lined Paper
Total items: 3Et avec :
int
2
Apples
50
Oranges
30Ta sortie doit être :
Apples: 50
Oranges: 30
Total items: 2Et avec :
priced
2
Widget
10
19.99
Gadget
5
49.50Ta sortie doit être :
Widget x10 @ 19.9
Gadget x5 @ 49.5
Total items: 2Remarque 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
}
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
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et modules GoPackages et importsNoms exportés et non exportésIntroduction à la POO en GoStructs comme classesDéfinir des méthodes sur des structsRécepteurs pointeurs ou par valeurInitialisation des structsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL’interface comme contratInterface vide (any)Assertion de typeCommutation de typeComposition d’interfacesInterfaces Stringer et ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter et SetterDissimulation de l’information en GoRécapitulatif – Fiches d’étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesSolution de contournement pour les méthodes génériquesRécapitulatif - Collection générique2Plongée approfondie dans les types et les structs
Types de base et compositesDéfinitions de types personnalisésTags de structStructs anonymesStructs imbriquésValeurs zéro et valeurs par défautRécapitulatif - Carnet de contacts5La composition plutôt que l’héritage
Pourquoi Go n’a pas d’héritageBases de l’inclusion de structsPromotion des méthodesInclure plusieurs structsInclusion ou agrégationMasquage des méthodes inclusesRécapitulatif : hiérarchie des employés8Gestion des erreurs et POO
L’interface errorTypes d’erreurs personnalisésEnrobage des erreurs (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - Analyseur de fichiers11Bibliothèque standard et POO
io.Reader et io.Writersort.InterfaceInterface fmt.Stringerencoding/json avec des structsInterface http.HandlerRécapitulatif - Modèles d’API REST14Modèles de conception – Partie 2
Modèle CommandeModèle AdaptateurModèle DécorateurModèle Méthode modèleModèle ÉtatModèle CompositeMiddleware comme décorateur3Pointeurs et mémoire
Notions de base des pointeurs en GoPointeurs vers des structuresPassage par valeur ou par référenceLa fonction new()Garbage collection en GoRécapitulatif - Constructeur de listes chaînées6Polymorphisme en Go
Polymorphisme via les interfacesDuck typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif – Processeur de paiements9Concurrence et POO
Bases des GoroutinesCanaux et communicationCanaux tamponnés ou non tamponnésInstruction selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures thread-safeRécapitulatif - Pool de workersEntraînez-vous par vous-même : Compilateur Go en ligne