Sobes.tech
Senior

Turlar yig'indisi nima va uni Go da qanday amalga oshirish mumkin?

sobes.tech AI

AIdan javob

Turlar turi (yoki belgilangan birlik, disjoint union) — bu bir nechta oldindan belgilangan variantlardan birini qabul qilishi mumkin bo'lgan ma'lumotlar turi. Haskell yoki Rust kabi tillardagi (enum) kabi to'g'ridan-to'g'ri qo'llab-quvvatlanmaydi, shuning uchun Go'da turli usullar bilan emulyatsiya qilish mumkin:

  1. Interfeyslar va turga ishonch (Type Assertion):

    Barcha mumkin bo'lgan variantlarni amalga oshiradigan interfeys yarating. Turlar to'plami qiymati bu interfeys bo'ladi, va aniq variantni aniqlash uchun turga ishonch yoki type switch ishlatiladi.

    package main
    
    import "fmt"
    
    // Shape - tur to'plamini ifodalovchi interfeys
    type Shape interface {
    	Area() float64
    }
    
    // Circle - variantlardan biri
    type Circle struct {
    	Radius float64
    }
    
    func (c Circle) Area() float64 {
    	return 3.14 * c.Radius * c.Radius
    }
    
    // Rectangle - boshqa 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 {
    		// turga switch yordamida aniqlash
    		switch v := s.(type) {
    		case Circle:
    			fmt.Printf("Doira radius %.2f, maydon: %.2f\n", v.Radius, v.Area())
    		case Rectangle:
    			fmt.Printf("To'rtburchak o'lchamlari %.2f x %.2f, maydon: %.2f\n", v.Width, v.Height, v.Area())
    		default:
    			fmt.Println("Noma'lum shakl")
    		}
    	}
    }
    
  2. Boolean flag'lar bilan tuzilgan strukturalar (kamdan-kam ishlatiladi):

    Struktura barcha mumkin bo'lgan variantlar uchun maydonlarni va qaysi variant faol ekanligini ko'rsatadigan boolean flag'larni o'z ichiga oladi. Bu xavfli va qo'llab-quvvatlash qiyin.

    package main
    
    import "fmt"
    
    type Result struct {
    	Value int  // muvaffaqiyatli natija uchun
    	Err   error // xato uchun
    
    	IsValue bool // Value faol ekanligini ko'rsatadigan flag
    	IsErr   bool // Err faol ekanligini ko'rsatadigan flag
    }
    
    func Process(input int) Result {
    	if input > 0 {
    		return Result{Value: input * 2, IsValue: true}
    	}
    	return Result{Err: fmt.Errorf("manfiy son: %d", input), IsErr: true}
    }
    
    func main() {
    	res1 := Process(10)
    	if res1.IsValue {
    		fmt.Printf("Natija: %d\n", res1.Value)
    	} else if res1.IsErr {
    		fmt.Printf("Xato: %v\n", res1.Err)
    	}
    
    	res2 := Process(-5)
    	if res2.IsValue {
    		fmt.Printf("Natija: %d\n", res2.Value)
    	} else if res2.IsErr {
    		fmt.Printf("Xato: %v\n", res2.Err)
    	}
    }
    
  3. Faol bo'lmagan maydonlar uchun null qiymat bilan tuzilgan strukturalar (ko'pincha Optional/Result uchun ishlatiladi):

    Struktura barcha variantlar uchun maydonlarni o'z ichiga oladi, lekin faqat biri null bo'ladi. Bu pointerlar yoki aniq "null" qiymatga ega bo'lgan turlar bilan yaxshi ishlaydi.

    package main
    
    import "fmt"
    
    // Option - Optional turidan Some/None emulyatsiyasi
    type Option struct {
    	Value *int // qiymat bo'lsa null emas
    }
    
    // None null Option yaratadi
    func None() Option {
    	return Option{}
    }
    
    // Some qiymat bilan Option yaratadi
    func Some(val int) Option {
    	return Option{Value: &val}
    }
    
    func main() {
    	opt1 := Some(10)
    	if opt1.Value != nil {
    		fmt.Printf("Qiymat: %d\n", *opt1.Value)
    	} else {
    		fmt.Println("Qiymat yo'q")
    	}
    
    	opt2 := None()
    	if opt2.Value != nil {
    		fmt.Printf("Qiymat: %d\n", *opt2.Value)
    	} else {
    		fmt.Println("Qiymat yo'q")
    	}
    }
    

Go'da tur to'plamini emulyatsiya qilishning eng idiomatik va xavfsiz usuli interfeyslar va type switch foydalanishdir. Bu faqat bitta variant mavjudligini ta'minlaydi va u bilan ishlashda tur xavfsizligini ta'minlaydi.