Menu
CoddyTech

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 impliquait soit de dupliquer les fonctions, soit d’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.

Imagine que tu cherches la valeur minimale dans une tranche. Sans les génériques, tu aurais 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, tu écris 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 à la compilation, ce qui vous garantit la sécurité sans surcharge à l’exécution.

Dans les prochaines leçons, nous étudierons 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 ! Tu vas créer une seule fonction générique qui peut trouver la valeur maximale d’une tranche, ce qui élimine le besoin de code en double pour différents types numériques.

Tu vas répartir ton code sur deux fichiers :

  • analyzer.go : définis ta fonction d’analyse générique.

    Crée 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ée é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 : lis les données d’entrée et montre tes fonctions génériques avec différents types.

    Lis un indicateur de type (int ou float), puis un nombre suivi d’autant de valeurs. Analyse les valeurs selon le type, appelle Max et Sum avec le type approprié, puis affiche les résultats.

    Pour une entrée entière, affiche :

    Max (int): [value]
    Sum (int): [value]

    Pour une entrée à virgule flottante, affiche 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, si l’entrée est :

int
4
15
8
23
11

Ta sortie doit être :

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

Et si l’entrée est :

float
3
4.5
9.2
6.8

Ta sortie doit être :

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

Remarque comme les mêmes fonctions génériques traitent 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 en matière de types pour chaque utilisation, alors que tu n’écris 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 d’éléments
	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 tranche d’entiers
		// TODO: Afficher les résultats au format "Max (int): [value]" et "Sum (int): [value]"

	} else if typeStr == "float" {
		// Lire les valeurs à virgule flottante
		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 tranche 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