Sobes.tech
Senior

Kas yra tipų suma ir kaip ją įgyvendinti Go kalboje?

sobes.tech AI

Atsakymas iš AI

Tipų suma (arba pažymėtas unijos, disjunktyvinės unijos) — tai duomenų tipas, kuris gali priimti vieną iš kelių iš anksto apibrėžtų variantų. Skirtingai nuo tipų produktų (struktūrų), kuriose reikšmė apima visus laukus vienu metu, tipų suma apima tik vieną iš galimų reikšmių.

Go kalboje nėra tiesioginės tipų sumų palaikymo kaip Haskell ar Rust (enum). Tipų sumas galima imituoti keliais būdais:

  1. Sąsajos ir tipo patvirtinimas (Type Assertion):

    Sukurkite sąsają, kuri įgyvendins visas galimas variacijas. Tipų suma reikšmė bus šios sąsajos įgyvendinimas, o konkrečios variacijos nustatymui naudojamas tipo patvirtinimas arba type switch.

    package main
    
    import "fmt"
    
    // Shape - sąsaja, atstovaujanti tipų sumą
    type Shape interface {
    	Area() float64
    }
    
    // Circle - viena iš variacijų
    type Circle struct {
    	Radius float64
    }
    
    func (c Circle) Area() float64 {
    	return 3.14 * c.Radius * c.Radius
    }
    
    // Rectangle - kita variacija
    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 {
    		// Tipų switch naudojimas variacijai nustatyti
    		switch v := s.(type) {
    		case Circle:
    			fmt.Printf("Apskritimas su spinduliu %.2f, plotas: %.2f\n", v.Radius, v.Area())
    		case Rectangle:
    			fmt.Printf("Stačiakampis su matmenimis %.2f x %.2f, plotas: %.2f\n", v.Width, v.Height, v.Area())
    		default:
    			fmt.Println("Nežinoma forma")
    		}
    	}
    }
    
  2. Struktūros su boolean ženklais (retai naudojama):

    Struktūra turi visus galimus variantus ir boolean ženklais nurodo, kuris variantas aktyvus. Tai nesaugus ir sunku palaikyti.

    package main
    
    import "fmt"
    
    type Result struct {
    	Value int  // Sėkmingo rezultato laukas
    	Err   error // Klaidos laukas
    
    	IsValue bool // Žymeklis, nurodantis, ar aktyvus Value
    	IsErr   bool // Žymeklis, nurodantis, ar aktyvus Err
    }
    
    func Process(input int) Result {
    	if input > 0 {
    		return Result{Value: input * 2, IsValue: true}
    	}
    	return Result{Err: fmt.Errorf("neigiamas skaičius: %d", input), IsErr: true}
    }
    
    func main() {
    	res1 := Process(10)
    	if res1.IsValue {
    		fmt.Printf("Rezultatas: %d\n", res1.Value)
    	} else if res1.IsErr {
    		fmt.Printf("Klaida: %v\n", res1.Err)
    	}
    
    	res2 := Process(-5)
    	if res2.IsValue {
    		fmt.Printf("Rezultatas: %d\n", res2.Value)
    	} else if res2.IsErr {
    		fmt.Printf("Klaida: %v\n", res2.Err)
    	}
    }
    
  3. Struktūros su nuline reikšme neaktyviems laukams (dažnai naudojama Optional/Result):

    Struktūra turi visus galimus laukus, bet tik vienas iš jų bus nulinės reikšmės. Gerai veikia su nuorodomis arba tipais, turinčiais aiškią "nulines" reikšmę.

    package main
    
    import "fmt"
    
    // Option - emuliacija Some/None iš pasirinktinio tipo
    type Option struct {
    	Value *int // Nulinė, jei yra reikšmė
    }
    
    // None sukuria nulinės reikšmės Option
    func None() Option {
    	return Option{}
    }
    
    // Some sukuria Option su reikšme
    func Some(val int) Option {
    	return Option{Value: &val}
    }
    
    func main() {
    	opt1 := Some(10)
    	if opt1.Value != nil {
    		fmt.Printf("Reikšmė yra: %d\n", *opt1.Value)
    	} else {
    		fmt.Println("Reikšmė nėra")
    	}
    
    	opt2 := None()
    	if opt2.Value != nil {
    		fmt.Printf("Reikšmė yra: %d\n", *opt2.Value)
    	} else {
    		fmt.Println("Reikšmė nėra")
    	}
    }
    

Geriausias ir saugiausias būdas imituoti tipų sumas Go kalboje — naudoti sąsajas ir type switch. Tai leidžia garantuoti, kad tik vienas variantas yra aktyvus, ir užtikrina tipų saugumą naudojant.