12-bo‘lim

Metodlar

Resiverli funksiyalar, qiymat va ko'rsatkich resiveri farqi, o'z turlaringizga metod qo'shish, String metodi va joylashtirilgan metodlar.

🕑 12 daqiqa o‘qish 📄 734 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Birinchi metod
  2. Qiymat va ko'rsatkich resiveri
  3. Qaysi birini tanlash
  4. Struktura bo'lmagan turlarga ham
  5. iota va metod birga
  6. String metodi maxsus
  7. Joylashtirilgan metodlar
  8. Metodni ustidan yozish
  9. Metod - oddiy qiymat
  10. Xulosa

Metod - bu resiveri bor funksiya. Resiver funksiya nomidan oldin, qavs ichida yoziladi.

Birinchi metod #

Go
package main

import "fmt"

type Talaba struct {
    Ism  string
    Ball int
}

func (t Talaba) Otdimi() bool {
    return t.Ball >= 60
}

func (t Talaba) Tavsif() string {
    return fmt.Sprintf("%s: %d ball", t.Ism, t.Ball)
}

func main() {
    a := Talaba{Ism: "Malika", Ball: 88}
    b := Talaba{Ism: "Aziza", Ball: 45}

    fmt.Println(a.Tavsif(), a.Otdimi())
    fmt.Println(b.Tavsif(), b.Otdimi())
}
Natija
Malika: 88 ball true
Aziza: 45 ball false

func (t Talaba) Otdimi() bool - Talaba turiga tegishli metod. t - resiver, ya'ni metod chaqirilgan qiymat.

Resiverga istalgan nom berish mumkin, lekin Go da odatda turning bosh harfi ishlatiladi: t, s, m.

Go da this yoki self yo'q

Java va Python da metod ichida this yoki self avtomatik paydo bo'ladi. Go da esa resiver ochiq e'lon qilinadi.

Bu ko'proq yozuv, lekin hech qanday sehr yo'q: metod - oddiy funksiya, uning birinchi argumenti shunchaki boshqa joyda yozilgan.

Qiymat va ko'rsatkich resiveri #

Go
package main

import "fmt"

type Hisoblagich struct {
    Soni int
}

func (h Hisoblagich) OshirNusxa() {
    h.Soni++
}

func (h *Hisoblagich) Oshir() {
    h.Soni++
}

func main() {
    x := Hisoblagich{}

    x.OshirNusxa()
    x.OshirNusxa()
    fmt.Println("nusxa resiveri:", x.Soni)

    x.Oshir()
    x.Oshir()
    fmt.Println("ko'rsatkich resiveri:", x.Soni)
}
Natija
nusxa resiveri: 0
ko'rsatkich resiveri: 2

Bu 8-bo'limdagi qoidaning aynan o'zi: qiymat resiveri nusxa oladi, shuning uchun o'zgarish yo'qoladi.

O'zgartiradigan har bir metod ko'rsatkich resiveriga ega bo'lishi kerak.

Go & belgisini o'zi qo'yadi

E'tibor bering: x.Oshir() deb yozildi, (&x).Oshir() emas - garchi metod *Hisoblagich ni kutsa ham.

Go buni o'zi hal qiladi: agar o'zgaruvchi manzil olinadigan bo'lsa, kompilyator & ni avtomatik qo'yadi. Teskarisi ham to'g'ri - ko'rsatkichda qiymat resiverli metodni chaqirsangiz, Go * ni o'zi qo'yadi.

Shuning uchun kundalik kodda farqni deyarli sezmaysiz. Lekin u interfeyslar bilan ishlaganda muhim bo'ladi - keyingi bo'limda.

Qaysi birini tanlash #

HolatResiver
Metod qiymatni o'zgartiradiKo'rsatkich
Struktura kattaKo'rsatkich
Turda boshqa ko'rsatkich metodlari borKo'rsatkich
Kichik, o'zgarmas turQiymat
Aralashtirmang

Agar turda kamida bitta ko'rsatkich resiverli metod bo'lsa, hammasini ko'rsatkich resiverli qiling.

Aralash holat chalkashlik tug'diradi: o'quvchi har bir metod uchun alohida o'ylab ko'rishi kerak bo'ladi, kompilyator esa ba'zi interfeys tekshiruvlarida kutilmaganda xato beradi.

Bu Go jamoasining rasmiy tavsiyasi.

Struktura bo'lmagan turlarga ham #

Go
package main

import "fmt"

type Harorat float64

func (h Harorat) Farengeyt() float64 {
    return float64(h)*1.8 + 32
}

func (h Harorat) Tavsif() string {
    switch {
    case h < 0:
        return "sovuq"
    case h < 20:
        return "salqin"
    case h < 30:
        return "iliq"
    default:
        return "issiq"
    }
}

func main() {
    bugun := Harorat(27.5)

    fmt.Println(bugun.Farengeyt())
    fmt.Println(bugun.Tavsif())
    fmt.Println(Harorat(-5).Tavsif())
}
Natija
81.5
iliq
sovuq

Metod faqat strukturalarga emas, har qanday nomlangan turga qo'shilishi mumkin.

type Harorat float64 - bu float64 ning yangi nomi emas, balki yangi tur. Unga o'z metodlaringizni bog'lash mumkin.

Nega Harorat(h) deb yozish kerak

float64(h)*1.8 qatoriga e'tibor bering. Harorat va float64 - turli turlar, shuning uchun 3-bo'limdagi qoida ishlaydi: aniq o'tkazish kerak.

Bu qulaysizlikdek tuyuladi, lekin foydasi bor: Harorat ni tasodifan Masofa yoki oddiy songa qo'shib yuborolmaysiz. Kompilyator bunga yo'l qo'ymaydi.

iota va metod birga #

Go
package main

import "fmt"

type Holat int

const (
    Yangi Holat = iota
    Jarayonda
    Bajarilgan
)

func (h Holat) String() string {
    switch h {
    case Yangi:
        return "yangi"
    case Jarayonda:
        return "jarayonda"
    case Bajarilgan:
        return "bajarilgan"
    default:
        return "noma'lum"
    }
}

func main() {
    h := Jarayonda

    fmt.Println(h)
    fmt.Printf("%v / %d\n", h, int(h))
    fmt.Println(Holat(99))
}
Natija
jarayonda
jarayonda / 1
noma'lum

Mana 3-bo'limda va'da qilingan narsa: iota bilan yaratilgan doimiylar endi o'z turiga va o'z nomiga ega.

String metodi maxsus #

Go
package main

import "fmt"

type Pul struct {
    Tiyin int
}

func (p Pul) String() string {
    return fmt.Sprintf("%d.%02d so'm", p.Tiyin/100, p.Tiyin%100)
}

func main() {
    narx := Pul{Tiyin: 1250075}

    fmt.Println(narx)
    fmt.Printf("%v\n", narx)
    fmt.Println("Narxi:", narx)

    royxat := []Pul{{Tiyin: 500}, {Tiyin: 125}}
    fmt.Println(royxat)
}
Natija
12500.75 so'm
12500.75 so'm
Narxi: 12500.75 so'm
[5.00 so'm 1.25 so'm]

String() string metodini yozsangiz, fmt paketi uni avtomatik ishlatadi - Println, Printf("%v"), hatto slice ichida ham.

Bu Go da interfeysning birinchi amaliy misoli. Keyingi bo'limda uning qanday ishlashini ko'ramiz.

String ichida Println chaqirmang

Bu juda oson tushib qoladigan tuzoq:

Go
func (p Pul) String() string {
    return fmt.Sprintf("%v", p)   // cheksiz rekursiya
}

%v String() ni chaqiradi, u yana %v ni... Dastur to'xtaguncha davom etadi va stack overflow bilan qulaydi.

Yechim: ichkarida turni o'zgartirib yuboring:

Go
func (p Pul) String() string {
    return fmt.Sprintf("%d tiyin", p.Tiyin)   // maydon, p emas
}

Joylashtirilgan metodlar #

Go
package main

import "fmt"

type Shaxs struct {
    Ism string
}

func (s Shaxs) Salomlash() string {
    return "Salom, men " + s.Ism
}

type Talaba struct {
    Shaxs
    Guruh string
}

func main() {
    t := Talaba{
        Shaxs: Shaxs{Ism: "Husanboy"},
        Guruh: "A-1",
    }

    fmt.Println(t.Salomlash())
    fmt.Println(t.Ism, t.Guruh)
}
Natija
Salom, men Husanboy
Husanboy A-1

Talaba da Salomlash metodi yozilmagan, lekin u ishlaydi.

Joylashtirilgan Shaxs turining metodlari Talaba ga ham o'tadi - 11-bo'limdagi maydonlar kabi.

Metodni ustidan yozish #

Go
package main

import "fmt"

type Shaxs struct {
    Ism string
}

func (s Shaxs) Salomlash() string {
    return "Salom, men " + s.Ism
}

type Oqituvchi struct {
    Shaxs
    Fan string
}

func (o Oqituvchi) Salomlash() string {
    return o.Shaxs.Salomlash() + ", " + o.Fan + " o'qituvchisiman"
}

func main() {
    o := Oqituvchi{
        Shaxs: Shaxs{Ism: "Dilnoza"},
        Fan:   "matematika",
    }

    fmt.Println(o.Salomlash())
    fmt.Println(o.Shaxs.Salomlash())
}
Natija
Salom, men Dilnoza, matematika o'qituvchisiman
Salom, men Dilnoza

Tashqi turda bir xil nomli metod yozsangiz, u ustunlik qiladi.

Ichkisiga baribir murojaat qilish mumkin: o.Shaxs.Salomlash().

Bu vorislik emas

Natija vorislikka o'xshaydi, lekin mexanizm boshqacha.

Vorislikda Oqituvchi bu Shaxs bo'lardi va uni Shaxs kutilgan har qanday joyga berish mumkin edi.

Go da esa Oqituvchi shunchaki ichida Shaxs saqlaydi. Kompilyator metod chaqiruvini avtomatik ravishda ichkariga yo'naltiradi, xolos.

Turlarni almashtirib ishlatish kerak bo'lsa, interfeys ishlatiladi - keyingi bo'limda.

Metod - oddiy qiymat #

Go
package main

import "fmt"

type Talaba struct {
    Ism string
}

func (t Talaba) Salomlash() string {
    return "Salom, " + t.Ism
}

func main() {
    t := Talaba{Ism: "Nodira"}

    f := t.Salomlash
    fmt.Println(f())

    g := Talaba.Salomlash
    fmt.Println(g(Talaba{Ism: "Kamola"}))
}
Natija
Salom, Nodira
Salom, Kamola

t.Salomlash - qavssiz yozilsa, u funksiya qiymati bo'ladi va t ni ichida saqlab qoladi.

Talaba.Salomlash esa resiverni birinchi argument sifatida qabul qiladigan oddiy funksiya. Bu metodlarning aslida nima ekanini ko'rsatadi.

Amaliy topshiriq
  1. Strukturaga ikkita qiymat resiverli metod yozing.
  2. Ko'rsatkich resiveri bilan maydonni o'zgartiring.
  3. Qiymat resiveri o'zgartira olmasligini isbotlang.
  4. type Harorat float64 yaratib, unga metod qo'shing.
  5. iota doimiylariga String metodini yozing.
  6. String metodi Println da avtomatik ishlashini ko'ring.
  7. Joylashtirish orqali metodni meros qilib oling.
  8. Tashqi turda bir xil nomli metod yozib, ustunligini ko'ring.
  9. Ichki metodga ochiq murojaat qiling.
  10. Metodni o'zgaruvchiga berib, keyin chaqiring.

Xulosa #

  • Metod - resiveri bor funksiya; resiver nomdan oldin, qavs ichida yoziladi.
  • Go da this yoki self yo'q - resiver ochiq e'lon qilinadi.
  • Qiymat resiveri nusxa oladi; o'zgartiradigan metod ko'rsatkich resiveri bilan yoziladi.
  • Bir turdagi metodlarning resiverlarini aralashtirmang.
  • Metodni har qanday nomlangan turga qo'shish mumkin, faqat strukturaga emas.
  • String() string metodi maxsus: fmt uni avtomatik ishlatadi - lekin ichida %v yozmang.
  • Joylashtirilgan turning metodlari tashqariga o'tadi; bir xil nomli metod esa ularni ustidan yozadi.
  • Metod - oddiy qiymat: uni o'zgaruvchiga berish mumkin.

Keyingi bo'limda interfeyslarni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.