Generic — l’essenza dei tipi generici e i parametri T

Autore: IT Sectr Pubblicato: 2026-06-18 Tempo di lettura: 10 min

Generic (programmazione generica) — è un meccanismo di Swift che consente di scrivere tipi e funzioni con un tipo parametrizzato . Invece di duplicare il codice per Int, String e strutture personalizzate, lo sviluppatore crea un’unica soluzione generica che funziona con qualsiasi tipo, mantenendo una tipizzazione rigorosa. Il compilatore sostituisce il tipo concreto al punto di utilizzo, garantendo sicurezza senza perdita di prestazioni. Secondo Swift Book, 2025, i parametri generici sono una delle caratteristiche chiave del linguaggio, alla base della libreria standard e di SwiftUI.

Punti Chiave

  • Generic — meccanismo di programmazione generica con parametri di tipo
  • Funzioni con parametri generici funzionano con qualsiasi tipo senza duplicare codice
  • Vincoli where restringono l’ambito dei generici ai tipi che soddisfano condizioni
  • Associated Types nei protocolli consentono ai protocolli di essere generici
  • Il compilatore genera codice specializzato per ogni tipo concreto

Cos’è Generic in Swift?

Generic (tipo generico) — è una costruzione sintattica di Swift che consente di scrivere codice flessibile e riutilizzabile con parametrizzazione dei tipi. Invece di un tipo concreto, viene scritto un segnaposto tra parentesi angolari — di solito , ma è possibile utilizzare qualsiasi nome. I generics sono alla base di SwiftUI (View, some View), della libreria standard (Array, Optional) e di Combine.

Perché servono i generics

Senza generics, si dovrebbero scrivere funzioni separate per ogni tipo: swapInts, swapStrings, swapDates. Una funzione generica swap sostituisce tutte e tre le varianti con una singola dichiarazione. Questo riduce la duplicazione, migliora la leggibilità e riduce la probabilità di errori durante la copia del codice.

swift
func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10
var y = 20
swapValues(&x, &y)

Il compilatore Swift genera codice specializzato per ogni utilizzo concreto di un generico. Ciò significa che la funzione generica swapValues non ha overhead rispetto a una funzione scritta a mano per Int. Swift non usa l’eliminazione dei tipi come Java — i generics esistono sia in fase di compilazione che di esecuzione (sebbene l’ottimizzazione possa specializzarli).

Funzioni Generiche con Parametro T

Funzioni generiche sono funzioni che accettano uno o più parametri di tipo. I parametri di tipo vengono specificati dopo il nome della funzione tra parentesi angolari: . Possono essere utilizzati nella firma: tipo dell’argomento, tipo restituito e all’interno del corpo della funzione.

Parametri di Tipo Multipli

Una funzione può avere multipli parametri generici. Ad esempio, la funzione findKey accetta un dizionario con chiavi K e valori V. Ogni parametro di tipo è univoco e può essere utilizzato nei vincoli.

swift
func findKey<K: Hashable, V>(
    for value: V,
    in dictionary: [K: V]
) -> K? where V: Equatable {
    for (key, dictValue) in dictionary {
        if dictValue == value {
            return key
        }
    }
    return nil
}

I vincoli K: Hashable e where V: Equatable garantiscono che findKey possa essere chiamata solo con un dizionario le cui chiavi siano hashable e i valori equatable. Tali vincoli non sono burocrazia ma una necessità: senza Hashable non è possibile indicizzare una ricerca per chiave, senza Equatable non è possibile confrontare value con dictValue.

Vincoli di Tipo con where

where — è una parola chiave di Swift che impone vincoli aggiuntivi ai parametri generici. A differenza della semplice specifica di un protocollo tra parentesi angolari (), where consente di esprimere condizioni più complesse: conformità a più protocolli, relazioni tra parametri di tipo e raffinamento degli associated types.

Sintassi di where

La clausola where viene scritta dopo la firma della funzione o del tipo, prima della parentesi graffa aperta. In where è possibile specificare che T: Comparable & Hashable (conforme a due protocolli simultaneamente), o che T.U == Int (concretizzare un associated type).

swift
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
}

extension Container where Item: Comparable {
    func isSorted() -> Bool {
        // Implementation available only if Item: Comparable
        return true
    }
}

L’estensione con where aggiunge metodi solo per quei tipi che soddisfano la condizione. Container otterrà il metodo isSorted, mentre Container no, perché Any non è Comparable. Questo è un potente meccanismo di funzionalità condizionale.

Associated Types nei Protocolli

Associated Types (tipi associati) — sono un modo per rendere un protocollo generico senza specificare un tipo concreto in fase di dichiarazione. Invece di , il protocollo dichiara un associatedtype, che viene concretizzato nell’implementazione. Ciò è particolarmente importante per le collezioni: il protocollo Sequence non sa quali elementi conterrà la sequenza.

Collegamento degli Associated Types con where

Usando where è possibile stabilire relazioni tra gli associated types di diversi protocolli. Ad esempio, si può richiedere che l’Item di un protocollo corrisponda a Iterator.Element di un altro. Ciò garantisce la compatibilità dei tipi a livello di compilatore.

swift
protocol StackProtocol {
    associatedtype Element
    mutating func push(_ item: Element)
    mutating func pop() -> Element?
}

struct IntStack: StackProtocol {
    typealias Element = Int
    private var items: [Int] = []
    
    mutating func push(_ item: Int) { items.append(item) }
    mutating func pop() -> Int? { items.popLast() }
}

IntStack concretizza Element come Int usando typealias. Il compilatore verifica che tutti i requisiti del protocollo siano soddisfatti con questo tipo. Senza associated types, si dovrebbe scrivere StackProtocol con un protocollo generico, ma Swift usa gli associated types per coerenza con i bridge Objective-C e una migliore leggibilità.

Generic in Estensioni e Subscript

Estensioni generiche consentono di aggiungere metodi a un tipo generico con vincoli aggiuntivi. Questo è il pattern di “conformità condizionale”, in cui un tipo ottiene funzionalità solo in determinate condizioni. Anche i subscript possono essere generici.

Subscript Generico

Un subscript può essere generico: accetta parametri generici tra parentesi angolari. Ciò è utile per l’accesso sicuro alle collezioni con indici arbitrari, dove l’indice può essere di diversi tipi.

swift
extension Array where Element: Numeric {
    func sum() -> Element {
        return reduce(0, +)
    }
}

extension Array {
    subscript<Indices: Sequence>(indices: Indices) -> [Element]
        where Indices.Element == Int {
        return indices.map { self[$0] }
    }
}

Questa costruzione fornisce una potente composizione: il metodo sum appare solo sugli array numerici, e il subscript con indici arbitrari funziona con qualsiasi sequenza di indici interi. Il compilatore gestisce la visibilità di questi membri in base alle condizioni where.

Errori Comuni con i Generici

Errori nell’uso dei generici sono spesso legati a vincoli errati o al tentativo di usare generici dove serve un tipo concreto. Esaminiamo tre scenari comuni affrontati dagli sviluppatori.

Parametrizzazione Eccessiva

Aggiungere parametri generici dove un tipo concreto è sufficiente è un anti-pattern. Se una funzione lavora sempre con String, non è necessario renderla . Ciò complica il codice senza vantaggi. I generici sono giustificati quando il tipo varia effettivamente, non per una “flessibilità futura” astratta.

Mancanza di Vincolo where

Chiamare un metodo su un parametro generico senza specificare che il metodo esiste è un errore. non può chiamare .count se non viene specificato che T: Collection. Aggiungi sempre vincoli ai parametri di tipo, altrimenti il compilatore rifiuterà il codice.

swift
// ❌ Error: value has no count method
func countElements<T>(value: T) -> Int { value.count }

// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }

L’errore è chiaro: il generico può essere qualsiasi tipo, e il compilatore non sa se ha count. Il vincolo Collection risolve il problema. Allo stesso modo per Equatable, Hashable, Numeric — specifica sempre il protocollo se prevedi di chiamare metodi o operatori sul parametro generico.

Domande Frequenti

Cos’è Generic in Swift in parole semplici?

Generic è un modo per scrivere codice che funziona con qualsiasi tipo, senza duplicare la stessa logica per Int, String e altri tipi. Invece di un tipo concreto, viene usato un segnaposto , che viene sostituito dal tipo reale al punto di utilizzo.

In cosa Generic differisce da Any?

Generic preserva le informazioni sul tipo concreto in fase di compilazione, consentendo al compilatore di verificare i tipi e generare codice ottimizzato. Any è un’eliminazione di tipo: qualsiasi valore può essere passato, ma il tipo viene perso ed è necessario un cast (as?).

Come vincolare un Generic con un protocollo?

Usa la sintassi T: SomeProtocol tra parentesi angolari o una clausola where separata where T: SomeProtocol. I vincoli garantiscono che il parametro generico supporti metodi e proprietà specifici.

Cos’è un Associated Type in un protocollo?

Associated Type (associatedtype) è un segnaposto per un tipo all’interno di un protocollo. Il protocollo non specifica un tipo concreto ma dichiara un associatedtype, che viene concretizzato nell’implementazione: Array ha Element, Dictionary ha Key e Value.

I generici sono più veloci o più lenti dei tipi concreti?

Swift compila il codice generico in versioni specializzate per ogni tipo concreto. In pratica, una funzione generica per Int non è più lenta di una funzione scritta a mano per Int. Non c’è overhead di astrazione.

Riepilogo

  • Generic — meccanismo di programmazione generica con parametro di tipo
  • Funzioni e tipi con parametri generici sostituiscono molteplici implementazioni duplicate
  • Vincoli where restringono l’ambito dei generici alle condizioni necessarie
  • Associated Types consentono ai protocolli di essere generici senza concretizzazione in dichiarazione
  • Estensioni con where aggiungono funzionalità solo quando le condizioni sono soddisfatte
  • Il compilatore genera codice specializzato — i generici non aggiungono overhead
  • Parametrizzazione eccessiva è un anti-pattern — usa i generici solo quando il tipo varia effettivamente

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche