8-bo‘lim

Ko'rsatkichlar

& va * amallari, qiymat bo'yicha uzatish, funksiyada o'zgartirish, nil ko'rsatkich, new va Go da ko'rsatkich arifmetikasi yo'qligi.

🕑 13 daqiqa o‘qish 📄 760 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo: hamma narsa nusxalanadi
  2. Yechim: manzilni uzatish
  3. Ko'rsatkichni ko'rish
  4. nil ko'rsatkich
  5. Funksiyada tuzilmani o'zgartirish
  6. Ko'rsatkich qaytaruvchi funksiya
  7. new funksiyasi
  8. Ko'rsatkich arifmetikasi yo'q
  9. Qachon ko'rsatkich ishlatish kerak
  10. Slice va map - alohida holat
  11. Xulosa

Ko'rsatkich - bu qiymatning manzili. Go da ular bor, lekin C dagiga qaraganda ancha xavfsiz.

Muammo: hamma narsa nusxalanadi #

Go
package main

import "fmt"

func oshir(son int) {
    son = son + 10
}

func main() {
    ball := 50
    oshir(ball)
    fmt.Println(ball)
}
Natija
50

Hech narsa o'zgarmadi. oshir funksiyasi ball ning nusxasini oldi va o'sha nusxani o'zgartirdi.

Go da hamma narsa qiymat bo'yicha uzatiladi. Istisno yo'q.

Yechim: manzilni uzatish #

Go
package main

import "fmt"

func oshir(son *int) {
    *son = *son + 10
}

func main() {
    ball := 50
    oshir(&ball)
    fmt.Println(ball)
}
Natija
60

Ikkita yangi belgi bor:

BelgiNomiNima qiladi
&ballManzil olishO'zgaruvchining manzilini beradi
*intKo'rsatkich turi"int ga ko'rsatkich"
*sonManzildan o'qishManzildagi qiymatga boradi

* belgisi ikki xil ma'noda ishlatiladi: tur yozilishida (*int) va qiymatga murojaatda (*son).

Ko'rsatkichni ko'rish #

Go
package main

import "fmt"

func main() {
    ball := 50
    manzil := &ball

    fmt.Println(ball)
    fmt.Println(*manzil)
    fmt.Println(manzil == &ball)

    *manzil = 75
    fmt.Println(ball)
}
Natija
50
50
true
75

manzil va &ball - bir xil narsa. *manzil orqali yozganingizda, ball ning o'zi o'zgaradi.

manzil := &ball manzil 0xc000018030 turi: *int ball 75 turi: int *manzil manzil o'zgaruvchining qayerdaligini saqlaydi, *manzil esa o'sha yerdagi qiymatga boradi manzil soni har bir ishga tushirishda boshqacha bo'ladi
Manzil qiymatini chop etmang

Yuqoridagi rasmda 0xc000018030 ko'rsatilgan, lekin bu son har bir ishga tushirishda boshqacha bo'ladi.

Shuning uchun bu darslikdagi misollarda manzilning o'zi hech qachon chiqarilmaydi - faqat *manzil orqali olingan qiymat yoki taqqoslash natijasi chiqariladi. Aks holda kutilgan natija sizda mos kelmasdi.

nil ko'rsatkich #

Go
package main

import "fmt"

func main() {
    var manzil *int

    fmt.Println(manzil == nil)

    ball := 42
    manzil = &ball
    fmt.Println(manzil == nil, *manzil)
}
Natija
true
false 42

Ko'rsatkichning nol qiymati - nil, ya'ni "hech qayerga ko'rsatmaydi".

nil ko'rsatkichdan o'qish dasturni to'xtatadi

Agar manzil nil bo'lsa va siz *manzil deb yozsangiz, dastur vahima (panic) bilan to'xtaydi:

KOD
panic: runtime error: invalid memory address or nil pointer dereference

Bu Go da eng ko'p uchraydigan ishlash vaqti xatolaridan biri.

Himoya usuli oddiy - ishlatishdan oldin tekshiring:

Go
if manzil != nil {
    fmt.Println(*manzil)
}

Vahima va undan qutulishni 15-bo'limda ko'ramiz.

Funksiyada tuzilmani o'zgartirish #

Go
package main

import "fmt"

type Talaba struct {
    Ism  string
    Ball int
}

func oshirNusxa(t Talaba) {
    t.Ball += 10
}

func oshirManzil(t *Talaba) {
    t.Ball += 10
}

func main() {
    talaba := Talaba{Ism: "Aziza", Ball: 80}

    oshirNusxa(talaba)
    fmt.Println("Nusxadan keyin:", talaba.Ball)

    oshirManzil(&talaba)
    fmt.Println("Manzildan keyin:", talaba.Ball)
}
Natija
Nusxadan keyin: 80
Manzildan keyin: 90

Bu ko'rsatkichlarning eng ko'p uchraydigan ishlatilishi. Strukturalarni 11-bo'limda batafsil o'rganamiz.

Go sizga qulaylik yaratadi

E'tibor bering: oshirManzil ichida (*t).Ball emas, oddiy t.Ball yozilgan.

Go ko'rsatkich orqali maydonga murojaat qilishni o'zi hal qiladi. C da t->Ball deb alohida belgi yozish kerak edi, Go da esa nuqta ikkala holatda ham ishlaydi.

Xuddi shunday, &talaba o'rniga metodlar bilan ishlaganda Go ko'pincha & ni ham o'zi qo'yadi - buni 12-bo'limda ko'ramiz.

Ko'rsatkich qaytaruvchi funksiya #

Go
package main

import "fmt"

type Talaba struct {
    Ism  string
    Ball int
}

func yangiTalaba(ism string) *Talaba {
    t := Talaba{Ism: ism, Ball: 0}
    return &t
}

func main() {
    a := yangiTalaba("Kamola")
    a.Ball = 95

    fmt.Println(a.Ism, a.Ball)
}
Natija
Kamola 95
C dan kelganlar uchun: bu xavfsiz

C da mahalliy o'zgaruvchining manzilini qaytarish jiddiy xato edi: funksiya tugagach, o'sha xotira yo'qolardi.

Go da bu mutlaqo xavfsiz. Kompilyator t ning manzili tashqariga chiqayotganini ko'radi va uni avtomatik ravishda uyumda (heap) joylashtiradi.

Bu tahlil qochib chiqish tahlili (escape analysis) deb ataladi. Siz hech narsa yozmaysiz - Go o'zi qaror qiladi va xotirani kerak bo'lmay qolganda avtomatik tozalaydi.

new funksiyasi #

Go
package main

import "fmt"

func main() {
    manzil := new(int)
    fmt.Println(*manzil)

    *manzil = 42
    fmt.Println(*manzil)

    ball := 42
    boshqa := &ball
    fmt.Println(*boshqa)
}
Natija
0
42
42

new(int) - yangi int yaratib, uning manzilini qaytaradi. Qiymat nol bo'ladi.

Amalda new kam ishlatiladi: &Talaba{...} shakli ancha qulayroq, chunki qiymatlarni darhol berish mumkin.

Ko'rsatkich arifmetikasi yo'q #

Go da ko'rsatkichni surib bo'lmaydi

C da ko'rsatkichga son qo'shib, qo'shni xotiraga o'tish mumkin edi:

C
p++;        // C da: keyingi elementga o'tadi
*(p + 3)    // C da: uchinchi qo'shnini o'qiydi

Go da bu umuman yo'q. manzil++ deb yozib bo'lmaydi.

Sabab - xavfsizlik. Ko'rsatkich arifmetikasi C dagi eng jiddiy xavfsizlik zaifliklarining manbai: chegaradan chiqib, begona xotirani o'qish yoki yozish.

Go da massiv bo'ylab yurish uchun slice ishlatiladi va u har safar chegarani tekshiradi. Buni keyingi bo'limda ko'ramiz.

Qachon ko'rsatkich ishlatish kerak #

HolatTavsiya
Funksiyada qiymatni o'zgartirish kerakKo'rsatkich
Katta struktura uzatilmoqdaKo'rsatkich
"Qiymat yo'q" holatini ko'rsatish kerakKo'rsatkich (nil)
Kichik struktura, faqat o'qiladiQiymat
int, string, boolQiymat
Shubhalansangiz - qiymat

Yangi boshlaganlar ko'pincha ko'rsatkichlarni haddan tashqari ko'p ishlatadi.

Go da kichik qiymatni nusxalash juda arzon - ko'pincha ko'rsatkich orqali murojaatdan tezroq, chunki protsessor keshiga yaxshiroq tushadi.

Qoida: o'zgartirish kerak bo'lmasa, oddiy qiymat yozing. Keyinroq kerak bo'lsa, * qo'shish oson.

Slice va map - alohida holat #

Go
package main

import "fmt"

func ozgartir(royxat []int) {
    royxat[0] = 999
}

func main() {
    sonlar := []int{1, 2, 3}
    ozgartir(sonlar)
    fmt.Println(sonlar)
}
Natija
[999 2 3]

Bu yerda & yozilmagan, lekin o'zgarish saqlanib qoldi.

Sababi: slice ichida haqiqiy ma'lumotga ko'rsatkich saqlanadi. Slice ning o'zi nusxalandi, lekin nusxa ham o'sha ma'lumotga ko'rsatadi.

Xuddi shunday map va kanal ham. Buni keyingi ikki bo'limda batafsil ko'ramiz.

Amaliy topshiriq
  1. Funksiyaga son berib, uni o'zgartirishga urinib ko'ring.
  2. Xuddi shuni ko'rsatkich bilan qayta yozing.
  3. & va * amallarini bitta misolda ishlating.
  4. nil ko'rsatkichni tekshirib ko'ring.
  5. nil dan o'qib, vahima matnini ko'ring.
  6. Strukturani funksiyada nusxa va manzil orqali o'zgartiring.
  7. Ko'rsatkich qaytaruvchi funksiya yozing.
  8. new(int) va &son farqini solishtiring.
  9. manzil++ yozib, xato matnini o'qing.
  10. Slice ni funksiyada o'zgartirib, natijani tekshiring.

Xulosa #

  • Go da hamma narsa qiymat bo'yicha uzatiladi - funksiya nusxa oladi.
  • &qiymat manzilni beradi, *manzil esa manzildagi qiymatga boradi.
  • Ko'rsatkichning nol qiymati - nil; undan o'qish vahima keltiradi.
  • Go ko'rsatkich orqali maydonga murojaatni o'zi hal qiladi: t.Ball yetarli.
  • Mahalliy o'zgaruvchining manzilini qaytarish xavfsiz - Go kerak bo'lsa uni uyumga ko'chiradi.
  • Ko'rsatkich arifmetikasi yo'q - bu ataylab, xavfsizlik uchun.
  • Shubhalansangiz qiymat ishlating; ko'rsatkich - o'zgartirish yoki katta struktura uchun.
  • slice, map va kanal ichida allaqachon ko'rsatkich bor.

Keyingi bo'limda massivlar va slicelarni 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.