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.

Embedding — struct 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

Inson — Talaba 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: Talaba — Insonning 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.