Ce este suma de tipuri și cum o implementăm în Go?
sobes.tech AI
Răspuns de la AI
Suma tipurilor (sau uniunea etichetată, uniunea disjunctă) este un tip de date care poate lua valoarea uneia dintre mai multe variante predefinite. Spre deosebire de produsul de tipuri (structuri), unde valoarea conține toate câmpurile simultan, suma de tipuri conține doar una dintre valorile posibile.
În Go, nu există suport direct pentru suma de tipuri ca în limbaje precum Haskell sau Rust (enum). Suma de tipuri poate fi emulată în mai multe moduri:
-
Interfețe și afirmație de tip (Type Assertion):
Crează o interfață, pe care toate variantele posibile o vor implementa. Valoarea sumei de tipuri va reprezenta această interfață, iar pentru a determina varianta specifică se folosește afirmația de tip sau
type switch.package main import "fmt" // Shape - interfață, reprezentând suma de tipuri type Shape interface { Area() float64 } // Circle - una dintre variante type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } // Rectangle - altă 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 { // Utilizarea switch-ului de tip pentru a determina varianta switch v := s.(type) { case Circle: fmt.Printf("Cerc cu raza %.2f, aria: %.2f\n", v.Radius, v.Area()) case Rectangle: fmt.Printf("Dreptunghi cu dimensiuni %.2f x %.2f, aria: %.2f\n", v.Width, v.Height, v.Area()) default: fmt.Println("Formă necunoscută") } } } -
Structuri cu câmpuri boolean (rar utilizate):
Structura conține câmpuri pentru toate variantele posibile și câmpuri boolean pentru a indica care variantă este activă. Este nesigur și dificil de întreținut.
package main import "fmt" type Result struct { Value int // Câmp pentru rezultat cu succes Err error // Câmp pentru eroare IsValue bool // Indicator dacă Value este activ IsErr bool // Indicator dacă Err este activ } func Process(input int) Result { if input > 0 { return Result{Value: input * 2, IsValue: true} } return Result{Err: fmt.Errorf("număr negativ: %d", input), IsErr: true} } func main() { res1 := Process(10) if res1.IsValue { fmt.Printf("Rezultat: %d\n", res1.Value) } else if res1.IsErr { fmt.Printf("Eroare: %v\n", res1.Err) } res2 := Process(-5) if res2.IsValue { fmt.Printf("Rezultat: %d\n", res2.Value) } else if res2.IsErr { fmt.Printf("Eroare: %v\n", res2.Err) } } -
Structuri cu valori nule pentru câmpurile inactive (adesea folosite pentru Optional/Result):
Structura conține câmpuri pentru toate variantele posibile, dar doar unul va fi nenul. Funcționează bine pentru pointeri sau tipuri cu valoare "nul" clar definit.
package main import "fmt" // Option - emulează Some/None din tipul opțional type Option struct { Value *int // Nenul dacă există valoare } // None creează o valoare nulă Option func None() Option { return Option{} } // Some creează un Option cu valoare func Some(val int) Option { return Option{Value: &val} } func main() { opt1 := Some(10) if opt1.Value != nil { fmt.Printf("Valoare: %d\n", *opt1.Value) } else { fmt.Println("Fără valoare") } opt2 := None() if opt2.Value != nil { fmt.Printf("Valoare: %d\n", *opt2.Value) } else { fmt.Println("Fără valoare") } }
Cel mai idiomatic și sigur mod de a emula suma de tipuri în Go este utilizarea interfețelor și type switch. Acest lucru asigură că doar o variantă este prezentă și oferă siguranță tipurilor în timpul utilizării.