Go Generics in 2026: Type Parameters, Constraints en Sollicitatievragen
Dit artikel behandelt essentiële Go generics sollicitatievragen voor 2026, van basis type parameters tot geavanceerde constraint-patronen.

Go 1.18 introduceerde generics in de taal in maart 2022, en sindsdien is deze functionaliteit doorontwikkeld via Go 1.21, 1.22 en verder. Dit artikel behandelt essentiële Go generics sollicitatievragen voor 2026, van basis type parameters tot geavanceerde constraint-patronen die hiring managers vaak vragen.
Go generics maken het mogelijk om functies en types te schrijven die werken met elk datatype terwijl compile-time type safety behouden blijft. In tegenstelling tot interfaces die runtime type assertions gebruiken, worden bij generics de types tijdens compile-time opgelost, wat betere performance en eerdere foutdetectie biedt.
Type Parameters in Go Begrijpen
Type parameters vormen de basis van Go generics. Een type parameter is een placeholder voor een type dat wordt gespecificeerd wanneer de generieke functie of het generieke type wordt gebruikt.
// 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
}De syntax met vierkante haken [T any] declareert een type parameter T die beperkt is door any. Go's compiler leidt het concrete type af uit de argumenten, waardoor expliciete typespecificatie in de meeste gevallen overbodig wordt.
Veelgestelde Sollicitatievraag: Wat is het Verschil tussen any en comparable?
Interviewers vragen vaak naar de ingebouwde constraints any en comparable. Het begrijpen van hun verschillen demonstreert solide generics-kennis.
// 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})De comparable constraint beperkt type parameters tot types die gelijkheidsoperatoren ondersteunen. Slices, maps en functies zijn uitgesloten omdat Go geen gelijkheid voor deze op taalniveau definieert.
Aangepaste Type Constraints Maken met Interfaces
Go gebruikt interfaces om aangepaste constraints te definiëren, waardoor uitgebreid wordt wat generieke functies kunnen accepteren. De Go-specificatie definieert hoe type-elementen werken binnen constraint-interfaces.
// 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
}Type unions met | specificeren welke exacte types aan de constraint voldoen. Deze aanpak biedt meer controle dan any terwijl runtime type assertions worden vermeden.
Sollicitatievraag: De ~ Tilde-operator in Constraints Uitleggen
De tilde-operator ~ in constraints matcht zowel een type als alle types met dat onderliggende type. Deze vraag test begrip van Go's typesysteem.
// ~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
}Zonder ~ zou de constraint int alleen het exacte type int matchen, niet aangepaste types zoals UserID. De tilde breidt de constraint uit om afgeleide types te includeren, waardoor generieke code flexibeler wordt.
Klaar om je Go gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Generieke Types: Structs en Methods
Generieke types gaan verder dan functies naar structs en methods. Dit patroon verschijnt frequent in datastructuur-implementaties.
// 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
}Merk op dat methods op generieke types de type parameter tussen haakjes moeten herhalen maar geen nieuwe type parameters kunnen introduceren. De receiver (s *Stack[T]) bindt de method aan de specifieke instantiatie van Stack.
Sollicitatievraag: Waarom Kunnen Methods Geen Eigen Type Parameters Hebben?
Go verbiedt extra type parameters op methods, een ontwerpbeslissing die ontwikkelaars verrast die komen van talen zoals Java of C#. De Go generics proposal legt uit dat deze beperking bestaat om het typesysteem hanteerbaar te houden.
// 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)
}De workaround gebruikt top-level functies met meerdere type parameters in plaats van methods. Dit ontwerp houdt method dispatch eenvoudig en vermijdt complexe interacties tussen receiver-types en method type parameters.
Type Inference en Constraint Inference
Go's type inference vermindert de verbositeit bij het aanroepen van generieke functies. Begrijpen wanneer expliciete type-argumenten nodig zijn helpt bij het schrijven van schonere code.
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)
}Type inference werkt van functie-argumenten naar type parameters. Wanneer de compiler types niet alleen uit argumenten kan afleiden, lossen expliciete type-argumenten tussen vierkante haken de ambiguïteit op.
Constraints Package: cmp en slices in de Standaardbibliotheek
Go 1.21 voegde het cmp-package toe met de Ordered constraint en vergelijkingsfuncties. Het slices-package demonstreert idiomatische generieke code in de standaardbibliotheek.
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
}De standaardbibliotheek-documentatie toont hoe deze packages generics benutten voor type-veilige operaties op geordende types. Bekendheid met deze packages demonstreert praktische generics-kennis voorbij theoretisch begrip.
Sollicitatievraag: Een Generieke Cache Implementeren
Een veelvoorkomende sollicitatie-oefening vraagt kandidaten om een generieke, thread-safe cache te implementeren. Dit test generics, concurrency met het sync-package en API-ontwerp.
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
}Deze implementatie gebruikt comparable voor keys (map-vereiste) en any voor values. De aparte cacheItem-struct toont hoe generieke types in elkaar kunnen worden genest. Thread-veiligheid komt van sync.RWMutex, een patroon dat wordt behandeld in Go-concurrency-sollicitaties.
Zero Values en Type Constraints
Het omgaan met zero values in generieke code vereist begrip van hoe Go variabelen van geparametriseerde types initialiseert.
// 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]
}Het var zero T-patroon creëert een zero value voor elk type T. Voor types waar nul een geldige waarde is (zoals 0 voor integers), onderscheidt de pointer-teruggevende variant tussen "niet gevonden" en "nul gevonden".
Geavanceerd: Meerdere Constraints Combineren
Complexe generieke functies kunnen vereisen dat types aan meerdere constraints voldoen. Go handelt dit af via interface-embedding.
// 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())
}
}Interface-embedding combineert constraints, waarbij types alle ingebedde interfaces moeten implementeren. De inline syntax interface{ A; B } biedt dezelfde functionaliteit zonder een benoemd constraint-type te declareren.
Conclusie
- Type parameters met
[T any]maken het mogelijk herbruikbare, type-veilige code te schrijven zonder runtime reflection comparablebeperkt tot types die==en!=ondersteunen, vereist voor map keys- De
~tilde matcht types met een specifiek onderliggend type, wat constraint-flexibiliteit uitbreidt - Aangepaste constraints gebruiken type unions (
int | string) om exacte toegestane types te specificeren - Methods kunnen geen eigen type parameters hebben; gebruik top-level functies als alternatief
- Standaardbibliotheek-packages
cmpenslicesdemonstreren idiomatische generieke patronen - Zero values via
var zero Thandelen lege of ontbrekende data af in generieke functies - Thread-veilige generieke datastructuren combineren generics met sync-primitieven
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Delen
Gerelateerde artikelen

Go Foutafhandeling in 2026: Patronen, Wrapping en Technische Interviewvragen
Uitgebreide gids over Go error handling: sentinel errors, error wrapping met fmt.Errorf, errors.Is/As en best practices voor technische interviews.

Go en gRPC in 2026: High-Performance Microservices en Sollicitatievragen
Uitgebreide Go gRPC-tutorial met Protocol Buffers, streaming RPC's, interceptors, productiepatronen en veelgestelde backend-sollicitatievragen voor 2026.

Go Design Patterns: Essentiële patronen en interviewvragen voor Go-ontwikkelaars
De zes belangrijkste Go design patterns met productieklare code: Functional Options, Strategy, Factory, Observer, Middleware en Struct Embedding. Inclusief veelgestelde interviewvragen.