Menu
Coddy logo textTech

Struct generiche

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

Proprio come le funzioni, anche le struct possono avere parametri di tipo. Una struct generica ti permette di creare strutture dati che funzionano con qualsiasi tipo, mantenendo la sicurezza dei tipi. È perfetta per creare contenitori riutilizzabili come pile, code o coppie chiave-valore.

Per definire una struct generica, inserisci il parametro di tipo dopo il nome della struct:

type Box[T any] struct {
    Value T
}

func main() {
    intBox := Box[int]{Value: 42}
    strBox := Box[string]{Value: "hello"}
    
    fmt.Println(intBox.Value)  // 42
    fmt.Println(strBox.Value)  // hello
}

A differenza delle funzioni generiche, devi specificare esplicitamente il tipo quando crei un’istanza di una struct generica. Go non può dedurre il tipo dal solo contesto.

Le struct generiche possono avere più parametri di tipo, il che le rende ideali per strutture come coppie o mappe:

type Pair[K, V any] struct {
    Key   K
    Value V
}

p := Pair[string, int]{Key: "age", Value: 25}
fmt.Printf("%s: %d\n", p.Key, p.Value)  // age: 25

Puoi anche applicare vincoli per assicurarti che i tipi memorizzati supportino operazioni specifiche:

type NumberBox[T int | float64] struct {
    Value T
}

nb := NumberBox[float64]{Value: 3.14}

Le struct generiche costituiscono le fondamenta per creare strutture dati riutilizzabili e sicure rispetto ai tipi in Go. Nella prossima lezione imparerai a definire metodi su questi tipi generici.

challenge icon

Sfida

Facile

Costruiamo un sistema di inventario generico in grado di tenere traccia di diversi tipi di articoli! Creerai strutture contenitore riutilizzabili che funzionano con qualsiasi tipo, mantenendo la piena sicurezza dei tipi.

Organizzerai il codice in due file:

  • inventory.go: Definisci le tue strutture contenitore generiche.

    Crea una struct generica Item[T any] con due campi: Name (string) e Data (di tipo T). Rappresenta qualsiasi articolo con dati associati di tipo flessibile.

    Crea una struct generica Container[T any] con un singolo campo Items che contiene uno slice di Item[T]. Questo contenitore può conservare più articoli dello stesso tipo di dati.

    Crea una struct generica vincolata PricedItem[T int | float64] con tre campi: Name (string), Quantity (int) e Price (di tipo T). Il vincolo garantisce che i prezzi siano sempre numerici.

    Implementa una funzione NewContainer[T any]() *Container[T] che crea e restituisce un puntatore a un Container vuoto.

    Implementa un metodo Add su *Container[T] che accetta un nome (string) e dei dati (T), crea un Item e lo aggiunge allo slice Items del contenitore.

    Implementa un metodo Count su Container[T] che restituisce il numero di articoli nel contenitore.

  • main.go: Mostra le tue strutture generiche con tipi diversi.

    Leggi un tipo di articolo (string, int oppure priced), quindi leggi un conteggio seguito dai dettagli degli articoli.

    Per il tipo string: Leggi coppie di nome e dati stringa. Crea un Container[string], aggiungi tutti gli articoli, quindi stampa ciascun articolo come [Name]: [Data] seguito dal conteggio totale.

    Per il tipo int: Leggi coppie di nome e dati interi. Crea un Container[int], aggiungi tutti gli articoli, quindi stampa ciascun articolo come [Name]: [Data] seguito dal conteggio totale.

    Per il tipo priced: Leggi terne di nome, quantità e prezzo (come float). Crea direttamente istanze di PricedItem[float64] e stampa ciascuna come [Name] x[Quantity] @ [Price], mostrando il prezzo con una cifra decimale.

    Stampa la riga del conteggio nel formato: Total items: [count]

Verranno forniti i seguenti input:

  • Riga 1: Tipo di articolo (string, int oppure priced)
  • Riga 2: Numero di articoli (intero)
  • Righe successive: Dettagli degli articoli in base al tipo

Per esempio, dato:

string
3
Book
Fiction Novel
Pen
Blue Ink
Notebook
Lined Paper

L'output dovrebbe essere:

Book: Fiction Novel
Pen: Blue Ink
Notebook: Lined Paper
Total items: 3

E dato:

int
2
Apples
50
Oranges
30

L'output dovrebbe essere:

Apples: 50
Oranges: 30
Total items: 2

E dato:

priced
2
Widget
10
19.99
Gadget
5
49.50

L'output dovrebbe essere:

Widget x10 @ 19.9
Gadget x5 @ 49.5
Total items: 2

Nota come la stessa struttura Container funzioni senza problemi sia con le stringhe sia con gli interi, mentre PricedItem usa un vincolo per garantire che per i prezzi si possano usare solo tipi numerici. Quando crei istanze di queste struct generiche, devi specificare esplicitamente il parametro di tipo.

Provalo tu

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leggi il tipo di elemento
	scanner.Scan()
	itemType := scanner.Text()
	
	// Leggi count
	scanner.Scan()
	count, _ := strconv.Atoi(scanner.Text())
	
	switch itemType {
	case "string":
		// TODO: Crea un Container[string] usando NewContainer
		// TODO: Leggi 'count' elementi (ognuno ha il nome su una riga e i dati sulla riga successiva)
		// TODO: Aggiungi ogni elemento al contenitore
		// TODO: Stampa ogni elemento nel formato "[Name]: [Data]"
		// TODO: Stampa "Total items: [count]" usando il metodo Count
		
	case "int":
		// TODO: Crea un Container[int] usando NewContainer
		// TODO: Leggi 'count' elementi (ognuno ha il nome su una riga e i dati interi sulla riga successiva)
		// TODO: Aggiungi ogni elemento al contenitore
		// TODO: Stampa ogni elemento nel formato "[Name]: [Data]"
		// TODO: Stampa "Total items: [count]" usando il metodo Count
		
	case "priced":
		// TODO: Crea una slice per contenere istanze di PricedItem[float64]
		// TODO: Leggi 'count' elementi (ognuno ha nome, quantità e prezzo su righe separate)
		// TODO: Crea un PricedItem[float64] per ciascuno e aggiungilo alla slice
		// TODO: Stampa ogni elemento nel formato "[Name] x[Quantity] @ [Price]", mostrando il prezzo con una cifra decimale
		// TODO: Stampa "Total items: [count]"
	}
	
	_ = scanner // Usa scanner per leggere l'input
	_ = count   // Usa count per il ciclo
}
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