Menu
Coddy logo textTech

Bases de la Réflexion

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 83 sur 107.

La réflexion permet à un programme d'examiner et de manipuler sa propre structure au moment de l'exécution. Le package reflect de Go offre cette capacité, vous permettant d'inspecter des types, de lire des champs de structures et d'appeler des méthodes de manière dynamique.

Les deux types fondamentaux de la réflexion sont reflect.Type et reflect.Value. Vous les obtenez en utilisant reflect.TypeOf() et reflect.ValueOf() :

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

Vous pouvez itérer sur les champs d'une structure pour examiner leurs noms, types et valeurs :

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Sortie :
// Name: Alice
// Age: 30

La réflexion est puissante mais comporte des compromis : elle contourne la vérification des types à la compilation, s'exécute plus lentement que l'accès direct et rend le code plus difficile à comprendre. Utilisez-la avec parcimonie pour des tâches telles que le marshaling JSON, le mapping ORM ou la création d'utilitaires génériques où le type n'est pas connu au moment de la compilation.

challenge icon

Défi

Facile

Construisons un inspecteur de structures qui utilise la réflexion pour examiner n'importe quelle structure et rapporter sa composition ! C'est un cas d'utilisation pratique de la réflexion : créer des utilitaires qui fonctionnent avec des types inconnus au moment de la compilation.

Vous organiserez votre code sur deux fichiers :

  • inspector.go : Créez votre utilitaire d'inspection basé sur la réflexion.

    Créez une fonction InspectStruct(v any) string qui utilise le package reflect pour examiner n'importe quelle structure qui lui est passée. Votre fonction doit retourner un rapport formaté contenant :

    • Le nom du type de la structure
    • Le genre (kind) de la structure (devrait être "struct")
    • Le nombre de champs
    • Pour chaque champ : le nom du champ, son type et sa valeur actuelle

    Le format de sortie doit être :

    Type: [TypeName]
    Kind: struct
    Fields: [count]
    - [FieldName] ([FieldType]): [Value]
    - [FieldName] ([FieldType]): [Value]
    ...

    Utilisez reflect.TypeOf() pour obtenir les informations de type et reflect.ValueOf() pour accéder aux valeurs des champs. Parcourez les champs en utilisant NumField(), Field(i) sur le type pour les métadonnées, et Field(i) sur la valeur pour les valeurs réelles.

  • main.go : Définissez des structures d'exemple et utilisez votre inspecteur.

    Lisez un type de structure (product ou employee) et les valeurs de ses champs, puis créez la structure appropriée et inspectez-la.

    Pour product : Créez une structure Product avec les champs Name (string), Price (float64) et InStock (bool). Lisez le nom, le prix et le statut du stock.

    Pour employee : Créez une structure Employee avec les champs ID (int), Name (string) et Department (string). Lisez l'ID, le nom et le département.

    Passez la structure créée à InspectStruct et affichez le résultat.

Les entrées suivantes seront fournies :

  • Ligne 1 : Type de structure (product ou employee)
  • Lignes suivantes : Valeurs des champs pour ce type de structure

Par exemple, avec :

product
Laptop
999.99
true

Votre sortie devrait être :

Type: Product
Kind: struct
Fields: 3
- Name (string): Laptop
- Price (float64): 999.99
- InStock (bool): true

Et avec :

employee
42
Alice Johnson
Engineering

Votre sortie devrait être :

Type: Employee
Kind: struct
Fields: 3
- ID (int): 42
- Name (string): Alice Johnson
- Department (string): Engineering

Et avec :

product
Headphones
79.50
false

Votre sortie devrait être :

Type: Product
Kind: struct
Fields: 3
- Name (string): Headphones
- Price (float64): 79.5
- InStock (bool): false

Remarquez comment votre inspecteur fonctionne avec différents types de structures sans connaître leur structure à l'avance — c'est toute la puissance de la réflexion ! La même fonction InspectStruct gère dynamiquement les structures Product et Employee.

Aide-mémoire

Le package reflect permet aux programmes d'examiner et de manipuler leur propre structure au moment de l'exécution.

Les deux types fondamentaux sont reflect.Type et reflect.Value, obtenus à l'aide de reflect.TypeOf() et reflect.ValueOf() :

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

Parcourez les champs de la structure pour examiner leurs noms, types et valeurs :

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Sortie :
// Name: Alice
// Age: 30

La réflexion contourne la vérification des types à la compilation, s'exécute plus lentement que l'accès direct et rend le code plus difficile à comprendre. Utilisez-la pour des tâches telles que le marshaling JSON, le mapping ORM ou la création d'utilitaires génériques où le type n'est pas connu au moment de la compilation.

Essayez vous-même

package main

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

// Structure Product avec les champs Name, Price, et InStock
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Structure Employee avec les champs ID, Name, et Department
type Employee struct {
	ID         int
	Name       string
	Department string
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Lire le type de structure
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Lire les champs du produit
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		priceStr, _ := reader.ReadString('\n')
		priceStr = strings.TrimSpace(priceStr)
		price, _ := strconv.ParseFloat(priceStr, 64)

		inStockStr, _ := reader.ReadString('\n')
		inStockStr = strings.TrimSpace(inStockStr)
		inStock, _ := strconv.ParseBool(inStockStr)

		// TODO: Créer une structure Product avec les valeurs lues
		// TODO: Appeler InspectStruct avec le produit et afficher le résultat

	} else if structType == "employee" {
		// Lire les champs de l'employé
		idStr, _ := reader.ReadString('\n')
		idStr = strings.TrimSpace(idStr)
		id, _ := strconv.Atoi(idStr)

		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		department, _ := reader.ReadString('\n')
		department = strings.TrimSpace(department)

		// TODO: Créer une structure Employee avec les valeurs lues
		// TODO: Appeler InspectStruct avec l'employé et afficher le résultat

	}
}
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