Menu
Coddy logo textTech

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.

challenge icon

Défi

Facile

Construisons 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) T qui trouve et renvoie la valeur maximale d’une tranche. La fonction doit fonctionner avec les types int et float64 grâce au paramètre de type T.

    Créez également une fonction générique Sum[T int | float64](values []T) T qui 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 (int ou float), puis lisez un nombre suivi d’autant de valeurs. Analysez les valeurs selon le type, appelez Max et Sum avec 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 (int ou float)
  • Ligne 2 : Nombre de valeurs (entier)
  • Lignes suivantes : Une valeur par ligne

Par exemple, avec :

int
4
15
8
23
11

Votre sortie doit être :

Max (int): 23
Sum (int): 57

Et avec :

float
3
4.5
9.2
6.8

Votre sortie doit être :

Max (float): 9.2
Sum (float): 20.5

Remarquez 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]"
	}
}
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