Menu
Coddy logo textTech

Nozioni di base sulla reflection

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 83 di 107.

La riflessione consente a un programma di esaminare e manipolare la propria struttura durante l'esecuzione. Il pacchetto reflect di Go offre questa funzionalità, permettendoti di ispezionare i tipi, leggere i campi delle struct e chiamare metodi dinamicamente.

I due tipi fondamentali nella reflection sono reflect.Type e reflect.Value. Li ottieni usando reflect.TypeOf() e 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

Puoi scorrere i campi della struct per esaminarne i nomi, i tipi e i valori:

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

La reflection è potente, ma comporta dei compromessi: aggira il controllo dei tipi in fase di compilazione, è più lenta dell’accesso diretto e rende il codice più difficile da comprendere. Usala con moderazione per attività come la serializzazione JSON, la mappatura ORM o la creazione di utilità generiche, quando il tipo non è noto in fase di compilazione.

challenge icon

Sfida

Facile

Costruiamo un ispettore di struct che usa la reflection per esaminare qualsiasi struct e descriverne la struttura! Questo è un caso d'uso pratico della reflection: creare utilità che funzionano con tipi sconosciuti al momento della compilazione.

Organizzerai il codice in due file:

  • inspector.go: crea la tua utilità di ispezione basata sulla reflection.

    Implementa una funzione InspectStruct(v any) string che usa il pacchetto reflect per esaminare qualsiasi struct che le viene passato. La funzione deve restituire un report formattato contenente:

    • Il nome del tipo della struct
    • Il kind della struct (dovrebbe essere "struct")
    • Il numero di campi
    • Per ogni campo: il nome, il tipo e il valore corrente

    Il formato dell'output dovrebbe essere:

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

    Usa reflect.TypeOf() per ottenere le informazioni sul tipo e reflect.ValueOf() per accedere ai valori dei campi. Itera sui campi usando NumField(), Field(i) sul tipo per i metadati e Field(i) sul valore per ottenere i valori effettivi.

  • main.go: definisci struct di esempio e usa il tuo ispettore.

    Leggi un tipo di struct (product o employee) e i valori dei suoi campi, poi crea la struct appropriata e ispezionala.

    Per product: crea una struct Product con i campi Name (string), Price (float64) e InStock (bool). Leggi il nome, il prezzo e lo stato delle scorte.

    Per employee: crea una struct Employee con i campi ID (int), Name (string) e Department (string). Leggi l'ID, il nome e il reparto.

    Passa la struct creata a InspectStruct e stampa il risultato.

Verranno forniti i seguenti input:

  • Riga 1: tipo di struct (product o employee)
  • Righe successive: valori dei campi per quel tipo di struct

Per esempio, dato:

product
Laptop
999.99
true

L'output dovrebbe essere:

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

E dato:

employee
42
Alice Johnson
Engineering

L'output dovrebbe essere:

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

E dato:

product
Headphones
79.50
false

L'output dovrebbe essere:

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

Nota come il tuo ispettore funzioni con diversi tipi di struct senza conoscerne in anticipo la struttura. Questa è la potenza della reflection! La stessa funzione InspectStruct gestisce dinamicamente sia le struct Product sia le struct Employee.

Provalo tu

package main

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

// Struct Product con i campi Name, Price e InStock
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Struct Employee con i campi ID, Name e Department
type Employee struct {
	ID         int
	Name       string
	Department string
}

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

	// Leggi il tipo di struct
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Leggi i campi del prodotto
		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: Crea una struct Product con i valori letti
		// TODO: Chiama InspectStruct con il prodotto e stampa il risultato

	} else if structType == "employee" {
		// Leggi i campi del dipendente
		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: Crea una struct Employee con i valori letti
		// TODO: Chiama InspectStruct con il dipendente e stampa il risultato

	}
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online