Introduction aux génériques
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 67 sur 107.
Avant Go 1.18, écrire du code réutilisable pour différents types signifiait soit dupliquer les fonctions, soit utiliser l’interface vide any avec des assertions de type. Les génériques résolvent ce problème en vous permettant d’écrire des fonctions et des types qui fonctionnent avec plusieurs types tout en conservant une sécurité de typage complète.
Considérons la recherche de la valeur minimale dans une tranche. Sans les génériques, vous auriez besoin de fonctions distinctes pour chaque type :
func MinInt(values []int) int {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}
func MinFloat64(values []float64) float64 {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}Avec les génériques, vous écrivez la logique une seule fois en utilisant un paramètre de type entre crochets :
func Min[T int | float64](values []T) T {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}Le [T int | float64] déclare un paramètre de type T qui peut être soit int, soit float64. Vous pouvez maintenant appeler Min([]int{3, 1, 2}) ou Min([]float64{3.5, 1.2}) avec la même fonction. Le compilateur vérifie les types au moment de la compilation, ce qui vous offre une sécurité sans surcharge à l’exécution.
Dans les prochaines leçons, nous explorerons en détail les paramètres de type, les contraintes et les structures génériques.
Défi
FacileConstruisons un analyseur de scores qui fonctionne avec des scores entiers et à virgule flottante grâce aux génériques ! Vous allez créer une seule fonction générique capable de trouver la valeur maximale dans une tranche, ce qui évite d’avoir dupliquer le code pour différents types numériques.
Vous allez organiser votre code dans deux fichiers :
analyzer.go: Définissez votre fonction d’analyse générique.Créez une fonction générique
Max[T int | float64](values []T) Tqui trouve et renvoie la valeur maximale d’une tranche. La fonction doit fonctionner avec les typesintetfloat64grâce au paramètre de typeT.Créez également une fonction générique
Sum[T int | float64](values []T) Tqui calcule et renvoie la somme de toutes les valeurs d’une tranche.main.go: Lisez l’entrée et montrez vos fonctions génériques avec différents types.Lisez un indicateur de type (
intoufloat), puis lisez un nombre suivi d’autant de valeurs. Analysez les valeurs selon le type, appelezMaxetSumavec le type approprié, puis affichez les résultats.Pour une entrée entière, affichez :
Max (int): [value] Sum (int): [value]Pour une entrée à virgule flottante, affichez avec une décimale :
Max (float): [value] Sum (float): [value]
Les entrées suivantes seront fournies :
- Ligne 1 : Indicateur de type (
intoufloat) - Ligne 2 : Nombre de valeurs (entier)
- Lignes suivantes : Une valeur par ligne
Par exemple, avec :
int
4
15
8
23
11Votre sortie doit être :
Max (int): 23
Sum (int): 57Et avec :
float
3
4.5
9.2
6.8Votre sortie doit être :
Max (float): 9.2
Sum (float): 20.5Remarquez comment les mêmes fonctions génériques gèrent les données entières et à virgule flottante : le paramètre de type [T int | float64] permet au compilateur de générer du code sûr du point de vue des types pour chaque utilisation, tandis que vous n’écrivez la logique qu’une seule fois.
Essayez vous-même
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Lire l'indicateur de type
typeStr, _ := reader.ReadString('\n')
typeStr = strings.TrimSpace(typeStr)
// Lire le nombre
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
if typeStr == "int" {
// Lire les valeurs entières
values := make([]int, count)
for i := 0; i < count; i++ {
line, _ := reader.ReadString('\n')
values[i], _ = strconv.Atoi(strings.TrimSpace(line))
}
// TODO: Appeler Max et Sum avec une slice d'entiers
// TODO: Afficher les résultats au format "Max (int): [value]" et "Sum (int): [value]"
} else if typeStr == "float" {
// Lire les valeurs flottantes
values := make([]float64, count)
for i := 0; i < count; i++ {
line, _ := reader.ReadString('\n')
values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
}
// TODO: Appeler Max et Sum avec une slice de float64
// TODO: Afficher les résultats avec une décimale au format "Max (float): [value]" et "Sum (float): [value]"
}
}
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