Wat is de som van types en hoe implementeer je deze in Go?
sobes.tech AI
Antwoord van AI
De som van (of getagde unie, disjuncte unie) is een gegevenstype dat een van de meerdere vooraf gedefinieerde opties kan aannemen. In tegenstelling tot het product van types (structuren), waarbij de waarde alle velden tegelijk bevat, bevat de som van types slechts één van de mogelijke waarden.
In Go is er geen directe ondersteuning voor sommen van types zoals in talen als Haskell of Rust (enum). De som van types kan op verschillende manieren worden geëmuleerd:
-
Interfaces en type assertion:
Maak een interface die alle mogelijke varianten implementeert. De waarde van de som van types zal deze interface zijn, en om de specifieke variant te bepalen wordt type assertion of
type switchgebruikt.package main import "fmt" // Shape - interface die de som van types representeert type Shape interface { Area() float64 } // Circle - een van de varianten type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } // Rectangle - een andere variant type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { shapes := []Shape{Circle{Radius: 5}, Rectangle{Width: 3, Height: 4}} for _, s := range shapes { // Gebruik van type switch om de variant te bepalen switch v := s.(type) { case Circle: fmt.Printf("Cirkel met straal %.2f, oppervlakte: %.2f\n", v.Radius, v.Area()) case Rectangle: fmt.Printf("Rechthoek met afmetingen %.2f x %.2f, oppervlakte: %.2f\n", v.Width, v.Height, v.Area()) default: fmt.Println("Onbekende vorm") } } } -
Structuren met boolean flags (zelden gebruikt):
De structuur bevat velden voor alle mogelijke varianten en boolean flags om aan te geven welke variant actief is. Dit is onveilig en moeilijk te onderhouden.
package main import "fmt" type Result struct { Value int // veld voor succesvol resultaat Err error // veld voor fout IsValue bool // vlag die aangeeft of Value actief is IsErr bool // vlag die aangeeft of Err actief is } func Process(input int) Result { if input > 0 { return Result{Value: input * 2, IsValue: true} } return Result{Err: fmt.Errorf("negatief getal: %d", input), IsErr: true} } func main() { res1 := Process(10) if res1.IsValue { fmt.Printf("Resultaat: %d\n", res1.Value) } else if res1.IsErr { fmt.Printf("Fout: %v\n", res1.Err) } res2 := Process(-5) if res2.IsValue { fmt.Printf("Resultaat: %d\n", res2.Value) } else if res2.IsErr { fmt.Printf("Fout: %v\n", res2.Err) } } -
Structuren met null-waarde voor inactieve velden (vaak gebruikt voor Optional/Result):
De structuur bevat velden voor alle varianten, maar slechts één daarvan zal niet null zijn. Dit werkt goed met pointers of types die een duidelijke "null"-waarde hebben.
package main import "fmt" // Option - emulatie van Some/None uit het optionele type type Option struct { Value *int // niet null als er een waarde is } // None creëert een null-waarde Option func None() Option { return Option{} } // Some creëert een Option met waarde func Some(val int) Option { return Option{Value: &val} } func main() { opt1 := Some(10) if opt1.Value != nil { fmt.Printf("Waarde: %d\n", *opt1.Value) } else { fmt.Println("Geen waarde") } opt2 := None() if opt2.Value != nil { fmt.Printf("Waarde: %d\n", *opt2.Value) } else { fmt.Println("Geen waarde") } }
De meest idiomatische en veilige manier om sommen van types in Go te emuleren, is het gebruik van interfacessen type switch. Dit zorgt ervoor dat slechts één variant aanwezig is en biedt typeveiligheid bij het werken ermee.