Menu
Coddy logo textTech

Introduzione ai tipi generici

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

Prima di Go 1.18, scrivere codice riutilizzabile per tipi diversi significava duplicare le funzioni oppure usare l’interfaccia vuota any con asserzioni di tipo. I generics risolvono questo problema permettendoti di scrivere funzioni e tipi che funzionano con più tipi mantenendo la piena sicurezza dei tipi.

Considera di trovare il valore minimo in una slice. Senza i generici, avresti bisogno di funzioni separate per ogni tipo:

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
}

Con i generics, scrivi la logica una sola volta usando un parametro di tipo tra parentesi quadre:

func Min[T int | float64](values []T) T {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

[T int | float64] dichiara un parametro di tipo T che può essere int oppure float64. Ora puoi chiamare Min([]int{3, 1, 2}) oppure Min([]float64{3.5, 1.2}) con la stessa funzione. Il compilatore controlla i tipi in fase di compilazione, così ottieni sicurezza senza overhead a runtime.

Nelle prossime lezioni esploreremo in dettaglio i parametri di tipo, i vincoli e le struct generiche.

challenge icon

Sfida

Facile

Costruiamo un analizzatore di punteggi che funziona sia con punteggi interi sia con numeri in virgola mobile, usando i generics! Creerai un'unica funzione generica in grado di trovare il valore massimo in una slice, eliminando la necessità di duplicare il codice per tipi numerici diversi.

Organizzerai il codice in due file:

  • analyzer.go: definisci la tua funzione generica di analisi.

    Crea una funzione generica Max[T int | float64](values []T) T che trova e restituisce il valore massimo in una slice. La funzione deve funzionare sia con i tipi int sia con float64 tramite il parametro di tipo T.

    Crea anche una funzione generica Sum[T int | float64](values []T) T che calcola e restituisce la somma di tutti i valori in una slice.

  • main.go: leggi l'input e mostra le tue funzioni generiche con tipi diversi.

    Leggi un indicatore di tipo (int o float), poi leggi un conteggio seguito da altrettanti valori. Analizza i valori in base al tipo, chiama sia Max sia Sum con il tipo appropriato e stampa i risultati.

    Per un input intero, stampa:

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

    Per un input in virgola mobile, stampa con una cifra decimale:

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

Verranno forniti i seguenti input:

  • Riga 1: indicatore di tipo (int o float)
  • Riga 2: conteggio dei valori (intero)
  • Righe successive: un valore per riga

Per esempio, dato:

int
4
15
8
23
11

Il tuo output dovrebbe essere:

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

E dato:

float
3
4.5
9.2
6.8

Il tuo output dovrebbe essere:

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

Nota come le stesse funzioni generiche gestiscano sia i dati interi sia quelli in virgola mobile: il parametro di tipo [T int | float64] consente al compilatore di generare codice sicuro rispetto ai tipi per ogni utilizzo, mentre tu scrivi la logica una sola volta.

Provalo tu

package main

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

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

	// Leggi l'indicatore del tipo
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// Leggi il conteggio
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	if typeStr == "int" {
		// Leggi i valori interi
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: Chiama Max e Sum con una slice di interi
		// TODO: Stampa i risultati nel formato "Max (int): [value]" e "Sum (int): [value]"

	} else if typeStr == "float" {
		// Leggi i valori in virgola mobile
		values := make([]float64, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
		}

		// TODO: Chiama Max e Sum con una slice di float64
		// TODO: Stampa i risultati con una cifra decimale nel formato "Max (float): [value]" e "Sum (float): [value]"
	}
}
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