Menu
Coddy logo textTech

Solution de contournement pour les méthodes génériques

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

Go présente une limitation notable : vous ne pouvez pas définir de méthodes avec leurs propres paramètres de type sur une structure. Bien que les structures génériques fonctionnent très bien, l’ajout d’une méthode qui introduit un nouveau paramètre de type n’est pas autorisé.

Ce code ne se compilera pas :

type Box[T any] struct {
    Value T
}

// ERROR: la méthode ne doit pas avoir de paramètres de type
func (b Box[T]) Convert[U any](fn func(T) U) U {
    return fn(b.Value)
}

La solution consiste à utiliser une fonction générique autonome plutôt qu’une méthode :

type Box[T any] struct {
    Value T
}

// Méthode ordinaire - utilise le paramètre de type de la structure
func (b Box[T]) Get() T {
    return b.Value
}

// Fonction autonome - peut avoir ses propres paramètres de type
func Convert[T, U any](b Box[T], fn func(T) U) U {
    return fn(b.Value)
}

func main() {
    intBox := Box[int]{Value: 42}
    
    // Utiliser la méthode
    fmt.Println(intBox.Get())  // 42
    
    // Utiliser la fonction autonome
    strResult := Convert(intBox, func(n int) string {
        return fmt.Sprintf("Number: %d", n)
    })
    fmt.Println(strResult)  // Number: 42
}

Les méthodes des structures génériques peuvent toujours utiliser le paramètre de type de la structure T. La restriction s’applique uniquement à l’introduction de paramètres de type supplémentaires dans la signature de la méthode.

Lorsque vous avez besoin de cette flexibilité, une fonction générique qui prend la structure comme premier argument obtient le même résultat.

challenge icon

Défi

Facile

Construisons une boîte à outils de transformation de données qui illustre la solution de contournement pour contourner la limitation de Go concernant les méthodes génériques ! Puisque les méthodes ne peuvent pas introduire de nouveaux paramètres de type, vous allez créer des fonctions génériques autonomes qui offrent la même flexibilité.

Vous allez organiser votre code sur deux fichiers :

  • wrapper.go : définissez votre conteneur générique et vos fonctions de transformation.

    Créez une structure générique Wrapper[T any] avec un seul champ Value de type T.

    Ajoutez une méthode Get à Wrapper[T] qui renvoie la valeur encapsulée. Cette méthode utilise le paramètre de type de la structure, ce qui est autorisé.

    Créez une fonction générique autonome Transform[T, U any](w Wrapper[T], fn func(T) U) U qui applique la fonction de transformation à la valeur du wrapper et renvoie le résultat. Cette fonction a besoin de son propre paramètre de type U pour le type de sortie, c'est pourquoi elle doit être une fonction autonome plutôt qu'une méthode.

    Créez une autre fonction autonome TransformToString[T any](w Wrapper[T]) string qui convertit la valeur encapsulée en chaîne à l'aide de fmt.Sprintf("%v", ...).

  • main.go : illustrez le modèle de solution de contournement avec différentes transformations.

    Lisez un indicateur de type (int ou string), puis lisez une valeur. Créez un Wrapper du type approprié.

    Pour une entrée int : créez un Wrapper[int], puis utilisez Transform pour doubler la valeur (en renvoyant un int), et utilisez TransformToString pour obtenir une représentation sous forme de chaîne.

    Pour une entrée string : créez un Wrapper[string], puis utilisez Transform pour obtenir la longueur de la chaîne (en renvoyant un int), et utilisez TransformToString pour obtenir la représentation sous forme de chaîne.

    Affichez les résultats dans ce format :

    Original: [value]
    Transformed: [transformed value]
    As String: [string representation]

Les entrées suivantes seront fournies :

  • Ligne 1 : indicateur de type (int ou string)
  • Ligne 2 : la valeur

Par exemple, avec :

int
25

Votre sortie doit être :

Original: 25
Transformed: 50
As String: 25

Et avec :

string
Hello World

Votre sortie doit être :

Original: Hello World
Transformed: 11
As String: Hello World

L'idée essentielle est que Transform prend un Wrapper[T] comme premier argument et introduit un nouveau paramètre de type U pour le type de retour. Ce qui ne serait pas possible en tant que méthode de la structure. Ce modèle vous offre la flexibilité des transformations génériques tout en respectant les contraintes du système de types de Go.

Essayez vous-même

package main

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

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Lire l'indicateur de type
	typeIndicator, _ := reader.ReadString('\n')
	typeIndicator = strings.TrimSpace(typeIndicator)
	
	// Lire la valeur
	value, _ := reader.ReadString('\n')
	value = strings.TrimSpace(value)
	
	if typeIndicator == "int" {
		// Analyser la valeur entière
		num, _ := strconv.Atoi(value)
		
		// TODO: Créer un Wrapper[int] avec le nombre analysé
		
		// TODO: Utiliser Transform pour doubler la valeur (indice : passer une fonction qui double)
		
		// TODO: Utiliser TransformToString pour obtenir la représentation sous forme de chaîne
		
		// TODO: Afficher les résultats dans le format requis :
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = num // Supprimez cette ligne lorsque vous utilisez num
	} else if typeIndicator == "string" {
		// TODO: Créer un Wrapper[string] avec la valeur
		
		// TODO: Utilisez Transform pour obtenir la longueur de la chaîne (indice : passez une fonction qui retourne len())
		
		// TODO: Utiliser TransformToString pour obtenir la représentation sous forme de chaîne
		
		// TODO: Afficher les résultats dans le format requis :
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = value // Supprimez cette ligne lorsque vous utilisez 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