# Go Generics nel 2026: Type Parameters, Constraints e Domande da Colloquio > Questo articolo copre le domande essenziali sui Go generics per i colloqui tecnici del 2026, dai type parameters base ai pattern avanzati di constraints. - Published: 2026-07-08 - Updated: 2026-07-08 - Author: SharpSkill - Reading time: 5 min --- Go 1.18 ha introdotto i generics nel linguaggio a marzo 2022, e da allora questa funzionalità si è evoluta attraverso Go 1.21, 1.22 e oltre. Questo articolo copre le domande essenziali sui Go generics per i colloqui tecnici del 2026, dai type parameters di base ai pattern avanzati di constraints comunemente richiesti nei colloqui. > **Cosa sono i Go Generics?** > > I Go generics permettono di scrivere funzioni e tipi che funzionano con qualsiasi tipo di dato mantenendo la type safety a compile-time. A differenza delle interface che usano type assertions a runtime, i generics risolvono i tipi a compile-time, fornendo migliori performance e rilevamento anticipato degli errori. ## Comprendere i Type Parameters in Go I type parameters costituiscono la base dei Go generics. Un type parameter è un segnaposto per un tipo che viene specificato quando la funzione o il tipo generico viene utilizzato. ```go // generic.go // Basic generic function with type parameter T func PrintSlice[T any](items []T) { for _, item := range items { fmt.Println(item) } } // Usage - type inference determines T automatically func main() { PrintSlice([]int{1, 2, 3}) // T is int PrintSlice([]string{"a", "b"}) // T is string } ``` La sintassi con parentesi quadre `[T any]` dichiara un type parameter `T` vincolato da `any`. Il compilatore Go inferisce il tipo concreto dagli argomenti, eliminando la necessità di specificare esplicitamente il tipo nella maggior parte dei casi. ## Domanda Comune da Colloquio: Qual è la Differenza tra `any` e `comparable`? Gli intervistatori chiedono frequentemente dei constraint built-in `any` e `comparable`. Comprendere le loro differenze dimostra una solida conoscenza dei generics. ```go // constraints.go // any: accepts all types (alias for interface{}) func Process[T any](value T) T { return value } // comparable: only types that support == and != func Contains[T comparable](slice []T, target T) bool { for _, v := range slice { if v == target { // This comparison requires comparable return true } } return false } // This compiles Contains([]int{1, 2, 3}, 2) // This fails: slices are not comparable // Contains([][]int{{1}, {2}}, []int{1}) ``` Il constraint `comparable` limita i type parameters ai tipi che supportano gli operatori di uguaglianza. Slice, map e funzioni sono escluse perché Go non definisce l'uguaglianza per questi a livello di linguaggio. ## Creare Type Constraints Personalizzati con le Interface Go utilizza le interface per definire constraint personalizzati, ampliando ciò che le funzioni generiche possono accettare. La [specifica Go](https://go.dev/ref/spec#Type_constraints) definisce come funzionano gli elementi di tipo all'interno delle interface di constraint. ```go // number.go // Custom constraint using type union type Number interface { int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64 } // Generic function constrained to numeric types func Sum[T Number](values []T) T { var total T for _, v := range values { total += v // + operator works because all Number types support it } return total } func main() { fmt.Println(Sum([]int{1, 2, 3})) // 6 fmt.Println(Sum([]float64{1.5, 2.5})) // 4.0 } ``` Le type union con `|` specificano quali tipi esatti soddisfano il constraint. Questo approccio fornisce più controllo rispetto ad `any` evitando le type assertions a runtime. ## Domanda da Colloquio: Spiegare l'Operatore Tilde `~` nei Constraints L'operatore tilde `~` nei constraints corrisponde sia a un tipo che a tutti i tipi con quel tipo sottostante. Questa domanda testa la comprensione del type system di Go. ```go // underlying.go // ~int matches int and any type with int as underlying type type Signed interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 } // Custom type with int as underlying type type UserID int type Temperature int64 func Abs[T Signed](value T) T { if value < 0 { return -value } return value } func main() { var id UserID = -42 var temp Temperature = -10 fmt.Println(Abs(id)) // 42 - works because ~int matches UserID fmt.Println(Abs(temp)) // 10 - works because ~int64 matches Temperature } ``` Senza `~`, il constraint `int` corrisponderebbe solo al tipo esatto `int`, non a tipi personalizzati come `UserID`. La tilde espande il constraint per includere i tipi derivati, rendendo il codice generico più flessibile. ## Tipi Generici: Struct e Metodi I tipi generici si estendono oltre le funzioni a struct e metodi. Questo pattern appare frequentemente nelle implementazioni di strutture dati. ```go // stack.go // Generic Stack type type Stack[T any] struct { items []T } // Push adds an element to the stack func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) } // Pop removes and returns the top element func (s *Stack[T]) Pop() (T, bool) { if len(s.items) == 0 { var zero T // Zero value for type T return zero, false } index := len(s.items) - 1 item := s.items[index] s.items = s.items[:index] return item, true } func main() { intStack := Stack[int]{} intStack.Push(10) intStack.Push(20) val, ok := intStack.Pop() // val=20, ok=true } ``` Da notare che i metodi sui tipi generici devono ripetere il type parameter tra parentesi ma non possono introdurre nuovi type parameters. Il receiver `(s *Stack[T])` lega il metodo all'istanziazione specifica di `Stack`. ## Domanda da Colloquio: Perché i Metodi Non Possono Avere i Propri Type Parameters? Go proibisce type parameters aggiuntivi sui metodi, una decisione di design che sorprende gli sviluppatori provenienti da linguaggi come Java o C#. La [proposta dei Go generics](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md) spiega che questa limitazione esiste per mantenere il type system trattabile. ```go // This is NOT valid Go code type Container[T any] struct { value T } // ERROR: methods cannot have type parameters // func (c *Container[T]) Transform[U any](fn func(T) U) U { // return fn(c.value) // } // Valid alternative: use a standalone function func Transform[T, U any](c *Container[T], fn func(T) U) U { return fn(c.value) } ``` La soluzione utilizza funzioni top-level con più type parameters invece dei metodi. Questo design mantiene semplice il method dispatch ed evita interazioni complesse tra tipi receiver e type parameters dei metodi. ## Type Inference e Constraint Inference La type inference di Go riduce la verbosità quando si chiamano funzioni generiche. Capire quando sono richiesti argomenti di tipo espliciti aiuta a scrivere codice più pulito. ```go // inference.go func Map[T, R any](input []T, transform func(T) R) []R { result := make([]R, len(input)) for i, v := range input { result[i] = transform(v) } return result } func main() { numbers := []int{1, 2, 3} // Type inference: T=int, R=string inferred from arguments strings := Map(numbers, func(n int) string { return fmt.Sprintf("%d", n) }) // Explicit types sometimes required for complex cases // Map[int, string](numbers, converter) } ``` La type inference lavora dagli argomenti della funzione ai type parameters. Quando il compilatore non riesce a inferire i tipi solo dagli argomenti, gli argomenti di tipo espliciti tra parentesi quadre risolvono l'ambiguità. ## Package dei Constraints: `cmp` e `slices` nella Libreria Standard Go 1.21 ha aggiunto il package `cmp` con il constraint `Ordered` e le funzioni di confronto. Il package `slices` dimostra codice generico idiomatico nella libreria standard. ```go // stdlib.go import ( "cmp" "slices" ) func main() { numbers := []int{3, 1, 4, 1, 5, 9} // slices.Sort uses cmp.Ordered constraint internally slices.Sort(numbers) // [1, 1, 3, 4, 5, 9] // Binary search on sorted slice index, found := slices.BinarySearch(numbers, 4) // cmp.Compare returns -1, 0, or 1 result := cmp.Compare(3, 5) // -1 // cmp.Or returns first non-zero value value := cmp.Or(0, 0, 42, 100) // 42 } ``` La [documentazione della libreria standard](https://pkg.go.dev/cmp) mostra come questi package sfruttano i generics per operazioni type-safe sui tipi ordinati. La familiarità con questi package dimostra conoscenza pratica dei generics oltre la comprensione teorica. ## Domanda da Colloquio: Implementare una Cache Generica Un esercizio comune nei colloqui chiede ai candidati di implementare una cache generica e thread-safe. Questo testa i generics, la concorrenza con il [package sync](/technologies/go/interview-questions/sync-primitives) e il design delle API. ```go // cache.go import ( "sync" "time" ) type Cache[K comparable, V any] struct { mu sync.RWMutex items map[K]cacheItem[V] } type cacheItem[V any] struct { value V expiration time.Time } func NewCache[K comparable, V any]() *Cache[K, V] { return &Cache[K, V]{ items: make(map[K]cacheItem[V]), } } func (c *Cache[K, V]) Set(key K, value V, ttl time.Duration) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = cacheItem[V]{ value: value, expiration: time.Now().Add(ttl), } } func (c *Cache[K, V]) Get(key K) (V, bool) { c.mu.RLock() defer c.mu.RUnlock() item, exists := c.items[key] if !exists || time.Now().After(item.expiration) { var zero V return zero, false } return item.value, true } ``` Questa implementazione usa `comparable` per le chiavi (requisito delle map) e `any` per i valori. Lo struct separato `cacheItem` mostra come i tipi generici possono essere annidati l'uno nell'altro. La thread safety deriva da `sync.RWMutex`, un pattern trattato nei [colloqui sulla concorrenza](/technologies/go/interview-questions/concurrency-patterns) di Go. ## Zero Values e Type Constraints Gestire gli zero values nel codice generico richiede la comprensione di come Go inizializza le variabili di tipi parametrizzati. ```go // zero.go // Return zero value when slice is empty func First[T any](slice []T) T { if len(slice) == 0 { var zero T // Zero value: 0 for int, "" for string, nil for pointers return zero } return slice[0] } // Alternative: return pointer to avoid ambiguity func FirstOrNil[T any](slice []T) *T { if len(slice) == 0 { return nil } return &slice[0] } ``` Il pattern `var zero T` crea uno zero value per qualsiasi tipo `T`. Per i tipi dove zero è un valore valido (come `0` per gli interi), la variante che restituisce un puntatore distingue tra "non trovato" e "trovato zero". ## Avanzato: Combinare Più Constraints Le funzioni generiche complesse possono richiedere che i tipi soddisfino più constraints. Go gestisce questo attraverso l'embedding delle interface. ```go // combined.go // Constraint requiring both ordering and string conversion type Stringable interface { String() string } type OrderedStringable interface { cmp.Ordered Stringable } // Alternative: use type parameters with multiple constraints inline func PrintSorted[T interface{ cmp.Ordered; fmt.Stringer }](items []T) { slices.Sort(items) for _, item := range items { fmt.Println(item.String()) } } ``` L'embedding delle interface combina i constraints, richiedendo che i tipi implementino tutte le interface incorporate. La sintassi inline `interface{ A; B }` fornisce la stessa funzionalità senza dichiarare un tipo constraint nominato. ## Conclusione - I type parameters con `[T any]` permettono di scrivere codice riutilizzabile e type-safe senza reflection a runtime - `comparable` limita ai tipi che supportano `==` e `!=`, richiesto per le chiavi delle map - La tilde `~` corrisponde ai tipi con uno specifico tipo sottostante, espandendo la flessibilità dei constraint - I constraint personalizzati usano type union (`int | string`) per specificare i tipi esatti permessi - I metodi non possono avere propri type parameters; usare funzioni top-level come alternativa - I package della libreria standard `cmp` e `slices` dimostrano pattern generici idiomatici - Gli zero values via `var zero T` gestiscono dati vuoti o mancanti nelle funzioni generiche - Le strutture dati generiche thread-safe combinano i generics con le primitive di sync --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/go/go-generics-type-parameters-constraints-interview-questions