Sobes.tech
Senior

Mis on tüüpide summa ja kuidas seda Go-s rakendada?

sobes.tech AI

Vastus AI-lt

Tüüpide summa (või märgitud unioon, disjunktne unioon) — see on andmetüüp, mis võib võtta üheks mitmest eelnevalt määratletud variandist. Erinevalt tüüpide toodetest (struktuurid), kus väärtus sisaldab kõiki välju korraga, sisaldab tüüpide summa ainult ühte võimalikku väärtust.

Go keeles ei ole otsest tuge tüüpide summade jaoks nagu Haskell või Rust (enum). Tüüpide summasid saab imiteerida mitmel viisil:

  1. Liidesed ja tüüpide kinnitamine (Type Assertion):

    Looge liides, mis realiseerib kõik võimalikud variandid. Tüüpide summa väärtus esindab seda liidest ning konkreetse variandi määramiseks kasutatakse tüüpide kinnitamist või type switch.

    package main
    
    import "fmt"
    
    // Shape - liides, mis esindab tüüpide summat
    type Shape interface {
    	Area() float64
    }
    
    // Circle - üks variant
    type Circle struct {
    	Radius float64
    }
    
    func (c Circle) Area() float64 {
    	return 3.14 * c.Radius * c.Radius
    }
    
    // Rectangle - teine 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 {
    		// Tüüpide switch variandi määramiseks
    		switch v := s.(type) {
    		case Circle:
    			fmt.Printf("Ring raadiusega %.2f, pindala: %.2f\n", v.Radius, v.Area())
    		case Rectangle:
    			fmt.Printf("Ristkülik mõõtmetega %.2f x %.2f, pindala: %.2f\n", v.Width, v.Height, v.Area())
    		default:
    			fmt.Println("Teadmata kuju")
    		}
    	}
    }
    
  2. Struktuurid koos bult-flagidega (harva kasutatakse):

    Struktuur sisaldab kõiki võimalikke välju ja bult-flag-e, mis näitavad, milline variant on aktiivne. See ei ole turvaline ja keeruline hooldada.

    package main
    
    import "fmt"
    
    type Result struct {
    	Value int  // Eduka tulemuse väli
    	Err   error // Viga väli
    
    	IsValue bool // Flag, mis näitab, kas aktiivne on Value
    	IsErr   bool // Flag, mis näitab, kas aktiivne on Err
    }
    
    func Process(input int) Result {
    	if input > 0 {
    		return Result{Value: input * 2, IsValue: true}
    	}
    	return Result{Err: fmt.Errorf("negatiivne arv: %d", input), IsErr: true}
    }
    
    func main() {
    	res1 := Process(10)
    	if res1.IsValue {
    		fmt.Printf("Tulemus: %d\n", res1.Value)
    	} else if res1.IsErr {
    		fmt.Printf("Viga: %v\n", res1.Err)
    	}
    
    	res2 := Process(-5)
    	if res2.IsValue {
    		fmt.Printf("Tulemus: %d\n", res2.Value)
    	} else if res2.IsErr {
    		fmt.Printf("Viga: %v\n", res2.Err)
    	}
    }
    
  3. Struktuurid koos nullväärtusega mitteaktiivsetel väljadel (tihti kasutatakse Optional/Result):

    Struktuur sisaldab kõiki võimalikke välju, kuid ainult üks neist on nullväärtus. See töötab hästi viitade või tüüpidega, millel on selge "nullväärtus".

    package main
    
    import "fmt"
    
    // Option - emuleerib Some/None valikulise tüübi
    type Option struct {
    	Value *int // Mitte-null, kui väärtus on olemas
    }
    
    // None loob nullväärtusega Option
    func None() Option {
    	return Option{}
    }
    
    // Some loob Option väärtusega
    func Some(val int) Option {
    	return Option{Value: &val}
    }
    
    func main() {
    	opt1 := Some(10)
    	if opt1.Value != nil {
    		fmt.Printf("Väärtus on: %d\n", *opt1.Value)
    	} else {
    		fmt.Println("Väärtus puudub")
    	}
    
    	opt2 := None()
    	if opt2.Value != nil {
    		fmt.Printf("Väärtus on: %d\n", *opt2.Value)
    	} else {
    		fmt.Println("Väärtus puudub")
    	}
    }
    

Kõige idiomaatilisem ja turvalisem viis tüüpide summa imiteerimiseks Go keeles on kasutada liideseid ja type switch. See võimaldab tagada, et on ainult üks variant, ja tagab tüübipõhise turvalisuse töö ajal.