Sobes.tech
Senior

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:

  1. 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ă")
    		}
    	}
    }
    
  2. 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)
    	}
    }
    
  3. 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.