Darsliklar Go Lang Embedding

Go Lang Go Lang Embedding

Embedding — Go’ning klassik meros (inheritance) o’rniga taklif qiladigan mexanizmi. Struct ichiga boshqa struct’ni nomsiz (faqat turi bilan) joylashtirish orqali, uning maydon va metodlari “ko’tarilgan” (promoted) holda avtomatik mavjud bo’ladi.

Embeddingstruct ichiga boshqa struct’ni maydon nomisiz, faqat turi bilan qo’shish. Bu meros emas, kompozitsiya — “bu — shu” emas, “bu o’zida shuni saqlaydi” munosabati.

Embedding orqali maydon va metod ko’tarilishi

package main

import "fmt"

type Inson struct {
    Ism string
}

func (i Inson) Tanishtir() {
    fmt.Println("Men", i.Ism)
}

type Talaba struct {
    Inson
    Ball int
}

func main() {
    t := Talaba{Inson: Inson{Ism: "Master Sherkulov"}, Ball: 95}

    t.Tanishtir()
    fmt.Println(t.Ism)
    fmt.Println(t.Ball)
}
Men Master Sherkulov
Master Sherkulov
95

InsonTalaba ichiga nomsiz joylashtirildi (Ism string kabi emas, Inson deb, faqat tur nomi bilan). Natijada Talaba Insonning Tanishtir() metodini va Ism maydonini to’g’ridan-to’g’ri, t.Inson.Ism deb yozmasdan, t.Ism shaklida meros oldi.

Bu meros emas — kompozitsiya

Muhim tushunchaviy farq: TalabaInsonning turi emas (Talaba Insonga is-a munosabatida emas), balki Insonni o’zida saqlaydi (has-a):

package main

import "fmt"

type Inson struct {
    Ism string
}

type Talaba struct {
    Inson
    Ball int
}

func qabulQil(i Inson) {
    fmt.Println("Qabul qilindi:", i.Ism)
}

func main() {
    t := Talaba{Inson: Inson{Ism: "Farrux"}, Ball: 90}
    qabulQil(t.Inson)
}
Qabul qilindi: Farrux

qabulQil(i Inson) funksiyasiga tning o’zini emas, aynan t.Insonni aniq uzatish kerak bo’ldi — C++’dagi ochiq (public) merosdan farqli, Go’da Talaba avtomatik Insonning o’rnini bosa olmaydi. Bu Go dizaynerlarining ataylab qilgan tanlovi: kompozitsiya moslashuvchan, lekin chalkash “is-a” ierarxiyasini keltirib chiqarmaydi.

Metodni qayta aniqlash (override’ga o’xshash)

Talaba o’zining Tanishtir metodini yozsa, u ichma-ich Insonnikini soyalantiradi (shadow qiladi):

package main

import "fmt"

type Inson struct {
    Ism string
}

func (i Inson) Tanishtir() {
    fmt.Println("Men", i.Ism, "— oddiy inson")
}

type Talaba struct {
    Inson
}

func (t Talaba) Tanishtir() {
    fmt.Println("Men", t.Ism, "— talaba")
}

func main() {
    t := Talaba{Inson: Inson{Ism: "Aziz"}}
    t.Tanishtir()
    t.Inson.Tanishtir()
}
Men Aziz — talaba
Men Aziz — oddiy inson

t.Tanishtir()Talabaning o’z metodini chaqiradi (ichma-ich Insonnikini “yashiradi”). Ichki Insonning asl metodiga esa t.Inson.Tanishtir() orqali hamon murojaat qilish mumkin — hech narsa yo’qolmadi, faqat ustma-ust qo’yildi.

Bir nechta struct’ni birga embed qilish

Struct bir nechta boshqa struct’ni bir vaqtda embed qila oladi — bu Ruby’dagi mixin’larga yaqin natija beradi:

package main

import "fmt"

type Suzuvchi struct{}

func (s Suzuvchi) Suz() {
    fmt.Println("Suzyapman")
}

type Yuruvchi struct{}

func (y Yuruvchi) Yur() {
    fmt.Println("Yuryapman")
}

type Odam struct {
    Suzuvchi
    Yuruvchi
}

func main() {
    o := Odam{}
    o.Suz()
    o.Yur()
}
Suzyapman
Yuryapman

Odam ikkita bo’sh struct’ni (Suzuvchi, Yuruvchi) embed qildi va ikkalasining metodlarini ham oldi. Bu naqsh Go’da “ko’p marotaba meros” o’rnini bosadigan, xavfsiz kompozitsiya usuli.