Sobes.tech
Senior

Mi az a típusösszeg és hogyan valósítjuk meg Go-ban?

sobes.tech MI

Válasz az MI-től

Típusok összege (vagy címkézett unió, diszjunkt unió) egy olyan adattípus, amely több előre meghatározott változat egyik értékét veheti fel. A típusok szorzatától (struktúrák), ahol az érték tartalmazza az összes mezőt egyszerre, az összegek csak egyet tartalmaznak a lehetséges értékek közül.

Go-ban nincs közvetlen támogatás a típusok összegéhez, mint például Haskell vagy Rust (enum). A típusok összegét többféleképpen lehet emulálni:

  1. Interfészek és típusállítás (Type Assertion):

    Hozzon létre egy interfészt, amelyet minden lehetséges változat megvalósít. A típusösszeg értéke ezt az interfészt fogja reprezentálni, és a konkrét változat meghatározásához típusállítást vagy type switch-t használ.

    package main
    
    import "fmt"
    
    // Shape - interfész, amely a típusösszeget reprezentálja
    type Shape interface {
    	Area() float64
    }
    
    // Circle - egyik változat
    type Circle struct {
    	Radius float64
    }
    
    func (c Circle) Area() float64 {
    	return 3.14 * c.Radius * c.Radius
    }
    
    // Rectangle - másik változat
    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ípus switch a változat meghatározásához
    		switch v := s.(type) {
    		case Circle:
    			fmt.Printf("Kör sugara %.2f, területe: %.2f\n", v.Radius, v.Area())
    		case Rectangle:
    			fmt.Printf("téglalap méretei %.2f x %.2f, területe: %.2f\n", v.Width, v.Height, v.Area())
    		default:
    			fmt.Println("Ismeretlen forma")
    		}
    	}
    }
    
  2. Boolean zászlókkal ellátott struktúrák (ritkán használják):

    A struktúra tartalmaz minden lehetséges változathoz mezőket és boolean zászlókat, amelyek jelzik, melyik változat aktív. Ez nem biztonságos és nehéz karbantartani.

    package main
    
    import "fmt"
    
    type Result struct {
    	Value int  // Sikeres eredmény mező
    	Err   error // Hiba mező
    
    	IsValue bool // Jelzi, hogy az érték aktív
    	IsErr   bool // Jelzi, hogy a hiba aktív
    }
    
    func Process(input int) Result {
    	if input > 0 {
    		return Result{Value: input * 2, IsValue: true}
    	}
    	return Result{Err: fmt.Errorf("negatív szám: %d", input), IsErr: true}
    }
    
    func main() {
    	res1 := Process(10)
    	if res1.IsValue {
    		fmt.Printf("Eredmény: %d\n", res1.Value)
    	} else if res1.IsErr {
    		fmt.Printf("Hiba: %v\n", res1.Err)
    	}
    
    	res2 := Process(-5)
    	if res2.IsValue {
    		fmt.Printf("Eredmény: %d\n", res2.Value)
    	} else if res2.IsErr {
    		fmt.Printf("Hiba: %v\n", res2.Err)
    	}
    }
    
  3. Null értékkel rendelkező struktúrák (gyakran Optional/Result):

    A struktúra tartalmaz minden lehetséges változathoz mezőket, de csak egy lesz nem null értékű. Jó pointerek vagy egyértelmű "null" értékű típusok esetén.

    package main
    
    import "fmt"
    
    // Option - emulálja a Some/None típusokat
    type Option struct {
    	Value *int // Nem null, ha érték van
    }
    
    // None null értéket hoz létre
    func None() Option {
    	return Option{}
    }
    
    // Some értékkel hoz létre Option-t
    func Some(val int) Option {
    	return Option{Value: &val}
    }
    
    func main() {
    	opt1 := Some(10)
    	if opt1.Value != nil {
    		fmt.Printf("Érték: %d\n", *opt1.Value)
    	} else {
    		fmt.Println("Nincs érték")
    	}
    
    	opt2 := None()
    	if opt2.Value != nil {
    		fmt.Printf("Érték: %d\n", *opt2.Value)
    	} else {
    		fmt.Println("Nincs érték")
    	}
    }
    

A legidiomatikusabb és biztonságosabb módja a típusok összegének emulálásának Go-ban az interfészek és type switch használata. Ez garantálja, hogy csak egy változat van jelen, és típusbiztonságot nyújt a vele való munkában.