Sobes.tech
Senior

Čo je súčet typov a ako ho implementovať v Go?

sobes.tech AI

Odpoveď od AI

Súčet typov (alebo označené zjednotenie, disjunktné zjednotenie) je dátový typ, ktorý môže nadobudnúť hodnotu jednej z viacerých preddefinovaných možností. Na rozdiel od produktu typov (štruktúr), kde hodnota obsahuje všetky polia súčasne, súčet typov obsahuje iba jednu z možných hodnôt.

V Go nie je priama podpora súčtu typov ako v jazykoch ako Haskell alebo Rust (enum). Súčet typov možno emulovať viacerými spôsobmi:

  1. Rozhrania a tvrdenie o type (Type Assertion):

    Vytvorte rozhranie, ktoré budú implementovať všetky možné varianty. Hodnota súčtu typov bude predstavovať toto rozhranie, a na určenie konkrétnej varianty sa používa tvrdenie o type alebo type switch.

    package main
    
    import "fmt"
    
    // Shape - rozhranie reprezentujúce súčet typov
    type Shape interface {
    	Area() float64
    }
    
    // Circle - jedna z možností
    type Circle struct {
    	Radius float64
    }
    
    func (c Circle) Area() float64 {
    	return 3.14 * c.Radius * c.Radius
    }
    
    // Rectangle - iná možnosť
    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 {
    		// Použitie switch na type na určenie možnosti
    		switch v := s.(type) {
    		case Circle:
    			fmt.Printf("Kruh s polomerom %.2f, plocha: %.2f\n", v.Radius, v.Area())
    		case Rectangle:
    			fmt.Printf("Obdĺžnik s rozmermi %.2f x %.2f, plocha: %.2f\n", v.Width, v.Height, v.Area())
    		default:
    			fmt.Println("Neznámy tvar")
    		}
    	}
    }
    
  2. Štruktúry s booleanovými vlajkami (zriedka používané):

    Štruktúra obsahuje polia pre všetky možné možnosti a booleanové vlajky na označenie, ktorá možnosť je aktívna. Je to nebezpečné a ťažké na údržbu.

    package main
    
    import "fmt"
    
    type Result struct {
    	Value int  // Pole pre úspešný výsledok
    	Err   error // Pole pre chybu
    
    	IsValue bool // Vlajka, ktorá ukazuje, či je aktívne Value
    	IsErr   bool // Vlajka, ktorá ukazuje, či je aktívne Err
    }
    
    func Process(input int) Result {
    	if input > 0 {
    		return Result{Value: input * 2, IsValue: true}
    	}
    	return Result{Err: fmt.Errorf("záporné číslo: %d", input), IsErr: true}
    }
    
    func main() {
    	res1 := Process(10)
    	if res1.IsValue {
    		fmt.Printf("Výsledok: %d\n", res1.Value)
    	} else if res1.IsErr {
    		fmt.Printf("Chyba: %v\n", res1.Err)
    	}
    
    	res2 := Process(-5)
    	if res2.IsValue {
    		fmt.Printf("Výsledok: %d\n", res2.Value)
    	} else if res2.IsErr {
    		fmt.Printf("Chyba: %v\n", res2.Err)
    	}
    }
    
  3. Štruktúry s nulovou hodnotou pre neaktívne polia (často používané pre Optional/Result):

    Štruktúra obsahuje polia pre všetky možné možnosti, ale iba jedno z nich bude nenulové. Funguje dobre pre ukazovatele alebo typy s jasnou "nulovou" hodnotou.

    package main
    
    import "fmt"
    
    // Option - emulácia Some/None z voliteľného typu
    type Option struct {
    	Value *int // Nenulové, ak je hodnota prítomná
    }
    
    // None vytvára nulovú hodnotu Option
    func None() Option {
    	return Option{}
    }
    
    // Some vytvára Option so hodnotou
    func Some(val int) Option {
    	return Option{Value: &val}
    }
    
    func main() {
    	opt1 := Some(10)
    	if opt1.Value != nil {
    		fmt.Printf("Hodnota: %d\n", *opt1.Value)
    	} else {
    		fmt.Println("Žiadna hodnota")
    	}
    
    	opt2 := None()
    	if opt2.Value != nil {
    		fmt.Printf("Hodnota: %d\n", *opt2.Value)
    	} else {
    		fmt.Println("Žiadna hodnota")
    	}
    }
    

Najidiomatičnejší a najbezpečnejší spôsob emulácie súčtu typov v Go je použitie rozhraní a type switch. To zabezpečuje, že je prítomná iba jedna z možností a poskytuje typovú bezpečnosť pri práci s ňou.