Direct naar de hoofdinhoud
Module 10 · Les 3 van 548/50 in de cursus~15 min
Modulelessen (3/5)

Generieke geneesmiddelen (Go 1.18+)

Sinds Go 1.18 (maart 2022) zijn typeparameters beschikbaar: functies en typen kunnen via typen worden geparametriseerd. Ze laten je Map, Filter, Set[T], LinkedList[T] schrijven zonder code te dupliceren en zonder interface{} + runtime-type beweringen.

Generieke functie: de syntaxis

Go
func Map[T, U any](s []T, f func(T) U) []U {
    out := make([]U, len(s))
    for i, v := range s {
        out[i] = f(v)
    }
    return out
}

doubled := Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
// doubled is []int{2, 4, 6}

Drie nieuwe elementen:

  • [T, U any] na de naam: declareert de typeparameters met hun beperkingen.
  • any = beperking die elk type accepteert (alias van interface{} sinds Go 1.18).
  • Gevolgtrekking: als u Map([]int{...}, ...) aanroept, hoeft u Map[int, int](...) niet te schrijven: de compiler leidt hieruit T=int, U=int af.

Soms is gevolgtrekking niet voldoende (bijvoorbeeld constructors zonder T argumenten) en is expliciete instantiatie nodig: New[*Server]().

Ingebouwde beperkingen

BeperkingBetekenis
anyElk type (== interface{}).
comparableTypen met == en !=: numeriek, string, bool, pointers, kanalen, vergelijkbare arrays/structs.

comparable staat gelijkheid toe, maar niet < of >.

Go
func Index[T comparable](s []T, x T) int {
    for i, v := range s {
        if v == x { return i }
    }
    return -1
}

Voor </> heeft u een aangepaste beperking nodig.

Aangepaste beperking: type vakbonden

Een beperking is een interface met "type element"-clausules:

Go
type Ordered interface {
    ~int | ~int64 | ~float64 | ~string
}

func Min[T Ordered](a, b T) T {
    if a < b { return a }
    return b
}
  • | = unie: accepteert elk van de vermelde typen.
  • ~int = "int of een ander type gedefinieerd als type X int" (met hetzelfde onderliggende type). Zonder ~, alleen exact int.

Een beperking kan ook methoden en type-elementen combineren:

Go
type Stringable interface {
    ~string
    Len() int
}

Generieke typen

Niet alleen functies: structs en interfaces kunnen ook typeparameters hebben.

Go
type Set[T comparable] struct {
    m map[T]struct{}
}

func NewSet[T comparable]() *Set[T] {
    return &Set[T]{m: make(map[T]struct{})}
}

func (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }
func (s *Set[T]) Has(v T) bool { _, ok := s.m[v]; return ok }

s := NewSet[string]()
s.Add("ada")

Methoden KUNNEN GEEN typeparameters toevoegen die verder gaan dan die van het type: func (s *Set[T]) MapTo[U any](...) compileert niet (opzettelijke ontwerpbeperking).

Wanneer generieke geneesmiddelen gebruiken?

Ja wanneer:

  • De logica is echt identiek voor verschillende typen (collecties, algoritmen, helpers zoals Map/Filter/Reduce).
  • Het alternatief is het dupliceren van code of het gebruiken van interface{} + typebeweringen (waarbij de typeveiligheid verloren gaat).

Nee wanneer:

  • Een interface met een of twee methoden is voldoende en beter leesbaar (io.Reader, fmt.Stringer).
  • Je parametriseert "omdat het kan": een enkele use case → maak er een concrete versie van.

Oefeningen

Oefening#go.m10.l3.e1
Pogingen: 0Laden…

Definieer de generieke functie Min[T Ordered](a, b T) T che ritorna il minore usando l'operatore <. Il constraint Besteld en già fornito.

Editor laden…

Oplossing beschikbaar na 3 pogingen

Oefening#go.m10.l3.e2
Pogingen: 0Laden…

Implementeer een kaart[T, U any](s []T, f func(T) U) []U: toepassing van een ander element en het nieuwe segment herstellen.

Editor laden…

Oplossing beschikbaar na 3 pogingen

Quiz#go.m10.l3.e3
Klaar

Ingebouwde quale constraint toestemming voor de operator == ma NON l'operator <?

Go
func Index[T ???](s []T, x T) int { ... }
Antwoordmogelijkheden