Tarkibga o'tish

Go’da massiv va make funksiyasi

Massiv (array) bir xil turdagi va soni o‘zgarmaydigan elementlarni ketma-ket saqlaydi. Masalan, haftaning har bir kunidagi harorat uchun doim yettita qiymat kerak. Bu qiymatlarni [7]float64 massivida saqlash mumkin.

Go’da massiv uzunligi uning turining bir qismi hisoblanadi. Shu sabab [3]int va [4]int boshqa-boshqa turlardir. Massiv yaratilgandan keyin unga yangi element uchun joy qo‘shib yoki uning uzunligini qisqartirib bo‘lmaydi.

Massivni e’lon qilish

Massiv turi [uzunlik]elementTuri ko‘rinishida yoziladi:

package main

import "fmt"

func main() {
    var ballar [4]int
    ballar[0] = 78
    ballar[1] = 91

    fmt.Println(ballar)
    fmt.Println("Uzunligi:", len(ballar))
}

Natija:

[78 91 0 0]
Uzunligi: 4

var ballar [4]int qatori to‘rtta int qiymati uchun joy ajratadi. Qiymat berilmagan elementlar dastlab 0 bo‘ladi. Chunki 0int turining nol qiymati. Nol qiymat o‘zgaruvchi yaratilganda Go avtomatik beradigan boshlang‘ich qiymatdir.

Massivdagi har bir element indeks, ya’ni uning tartib raqami orqali tanlanadi. Indeks 0 dan boshlanadi. Demak, to‘rtta elementli massivning indekslari 0, 1, 2 va 3 bo‘ladi. Misolda dastlabki ikkita elementga qiymat berilgan. Qolgan ikkita element esa 0 bo‘lib qolgan.

Warning

ballar[4] deb yozib bo‘lmaydi, chunki bu massivda 4-indeks yo‘q. Chegaradan tashqaridagi indeks kodning o‘zida aniq yozilsa, kompilyator xato beradi. Indeks dastur ishlayotgan paytda hisoblanib, chegaradan chiqib ketsa, dastur panic bilan to‘xtaydi.

Massiv literalari

Qiymatlarni e’lon qilish paytida berish mumkin:

package main

import "fmt"

func main() {
    ranglar := [3]string{"qizil", "yashil", "ko‘k"}
    sonlar := [...]int{10, 20, 30, 40}

    fmt.Println(ranglar)
    fmt.Println(sonlar, len(sonlar))
}

Natija:

[qizil yashil ko‘k]
[10 20 30 40] 4

[3]string yozuvida massiv uzunligi aniq ko‘rsatilgan. [...]int ichidagi ... esa uzunlikni berilgan elementlar sonidan aniqlashni kompilyatorga topshiradi. sonlar ichida to‘rtta element borligi uchun uning turi [4]int bo‘ladi.

Massiv bo‘ylab yurish

Massivning barcha elementlarini ketma-ket o‘qish uchun range ishlatiladi. U siklning har bir iteratsiyasida element indeksi va qiymatini beradi. Iteratsiya — sikl tanasining bir marta bajarilishi.

package main

import "fmt"

func main() {
    ballar := [4]int{78, 91, 85, 88}
    yigindi := 0

    for indeks, ball := range ballar {
        fmt.Printf("%d-indeks: %d\n", indeks, ball)
        yigindi += ball
    }

    fmt.Println("O‘rtacha:", float64(yigindi)/float64(len(ballar)))
}

Natija:

0-indeks: 78
1-indeks: 91
2-indeks: 85
3-indeks: 88
O‘rtacha: 85.5

Sikl har bir ball qiymatini yigindi o‘zgaruvchisiga qo‘shadi. O‘rtacha qiymatni hisoblash uchun yig‘indi elementlar soniga bo‘linadi. Bo‘lishdan oldin ikkala qiymat ham float64 turiga o‘tkazilgan. Aks holda Go ikkita int qiymatini bo‘ladi va natijaning kasr qismini tashlab yuboradi.

Massivdan nusxa olish

Massivni boshqa o‘zgaruvchiga berganda Go uning barcha elementlaridan alohida nusxa oladi. Nusxadagi elementni o‘zgartirish dastlabki massivga ta’sir qilmaydi:

package main

import "fmt"

func main() {
    asl := [3]int{1, 2, 3}
    nusxa := asl
    nusxa[0] = 99

    fmt.Println("Asl:", asl)
    fmt.Println("Nusxa:", nusxa)
}

Natija:

Asl: [1 2 3]
Nusxa: [99 2 3]

Misolda asl va nusxa bir xil qiymatlardan tuzilgan ikkita mustaqil massiv bo‘ldi. Shu sabab nusxa[0] o‘zgartirilganda asl[0] avvalgi qiymatini saqlab qoldi.

Massiv funksiyaga argument sifatida uzatilganda ham to‘liq nusxalanadi. Argument — funksiyaga chaqirish paytida beriladigan qiymat. Katta massivni funksiyaga qayta-qayta uzatish ortiqcha nusxalar yaratishi mumkin. Bunday holatda ko‘pincha slice ishlatiladi.

Massivlarni taqqoslash

Bir xil turdagi ikkita massivni == va != operatorlari bilan taqqoslash mumkin. Go bir xil indeksda turgan elementlarni ketma-ket solishtiradi. Barcha mos elementlar teng bo‘lsagina massivlar teng hisoblanadi.

Bu imkoniyat massiv elementining turiga ham bog‘liq. Masalan, int va string qiymatlarini taqqoslash mumkin. Shuning uchun ulardan tuzilgan massivlar ham taqqoslanadi. Element turi taqqoslanmaydigan bo‘lsa, massivni ham == bilan tekshirib bo‘lmaydi.

make massiv uchun ishlatilmaydi

make Go’ga o‘rnatilgan funksiyalardan biridir. U slice, map va channel turlarini yaratib, ishlashga tayyorlaydi. Slice — elementlar sonini o‘zgartirish mumkin bo‘lgan ketma-ketlik. map kalit va qiymat juftlarini saqlaydi, channel esa goroutinlar orasida qiymat uzatishda ishlatiladi.

Massivga make kerak emas. Massiv e’lon qilinganda uning barcha elementlari uchun joy darhol ajratiladi.

Shuning uchun quyidagi kod kompilyatsiyadan o‘tmaydi:

// Kompilyatsiya xatosi:
// numbers := make([5]int)

Massivdan farqini ko‘rish uchun make yordamida slice yaratamiz. Bunda ikkinchi argument slice uzunligini, uchinchi argument esa sig‘imini bildiradi. Sig‘im — slice asosidagi xotirada nechta element uchun joy borligini ko‘rsatuvchi qiymat.

package main

import "fmt"

func main() {
    sonlar := make([]int, 3, 5)
    sonlar[0] = 10

    fmt.Println(sonlar)
    fmt.Println("Uzunlik:", len(sonlar), "Sig‘im:", cap(sonlar))
}

Natija:

[10 0 0]
Uzunlik: 3 Sig‘im: 5

make([]int, 3, 5) uzunligi 3, sig‘imi 5 bo‘lgan slice yaratadi. Uning hozir foydalanish mumkin bo‘lgan uchta elementi bor. Bu elementlar dastlab 0 qiymatini oladi. Shu paytda faqat 0, 1 va 2 indekslariga murojaat qilish mumkin.

Sig‘im 5 ekanligi sonlar[3] indeksi hoziroq mavjud degani emas. Avval slice uzunligini append() yordamida yoki sig‘im chegarasida qayta kesish orqali oshirish kerak. Slice uzunligi va sig‘imi keyingi darsda batafsil tushuntiriladi.

Qachon massiv ishlatiladi?

Elementlar soni oldindan ma’lum va o‘zgarmas bo‘lsa, massivdan foydalanish qulay. Masalan, IPv4 manzili doim to‘rtta baytdan iborat. Uni [4]byte turi bilan ifodalash mumkin. 32 baytli xesh qiymati uchun esa [32]byte mos keladi.

Elementlar soni dastur ishlashi davomida ko‘payishi yoki kamayishi mumkin bo‘lsa, odatda slice ishlatiladi. Demak, massiv va slice orasidagi tanlov avvalo elementlar soni o‘zgarishi yoki o‘zgarmasligiga bog‘liq.

Qo‘shimcha misollar

1. Uzunlikni kompilyatorga aniqlatish

package main

import "fmt"

func main() {
    ranglar := [...]string{"qizil", "yashil", "ko‘k"}
    fmt.Printf("%T, uzunligi: %d\n", ranglar, len(ranglar))
}

Natija:

[3]string, uzunligi: 3

... yozuvi massiv uzunligini qo‘lda kiritmaslik imkonini beradi. Kompilyator uchta rang borligini ko‘radi va ranglar turini [3]string deb belgilaydi.

2. Indeksli massiv literali

package main

import "fmt"

func main() {
    sonlar := [6]int{1: 10, 4: 40}
    fmt.Println(sonlar)
}

Natija:

[0 10 0 0 40 0]

Massiv literalida faqat kerakli indekslarga qiymat berish ham mumkin. Bu misolda 1-indeksga 10, 4-indeksga esa 40 yoziladi. Qolgan elementlar int turining nol qiymati — 0 bilan to‘ldiriladi.

3. Massivlarni tenglik bilan solishtirish

package main

import "fmt"

func main() {
    a := [3]int{1, 2, 3}
    b := [3]int{1, 2, 3}
    fmt.Println(a == b)
}

Natija:

true

a va b bir xil [3]int turiga ega. Ularning mos indekslaridagi qiymatlar ham teng. Shu sabab dastur true qiymatini ekranga chiqaradi.

4. Massiv nusxasini o‘zgartirish

package main

import "fmt"

func main() {
    asl := [3]int{2, 4, 6}
    nusxa := asl
    for i := range nusxa {
        nusxa[i] *= 2
    }
    fmt.Println("Asl:", asl)
    fmt.Println("Nusxa:", nusxa)
}

Natija:

Asl: [2 4 6]
Nusxa: [4 8 12]

nusxa := asl barcha elementlardan nusxa oladi. Sikl faqat nusxa elementlarini ikki baravar oshiradi. Natijada asl o‘z holicha qoladi.

5. Massiv yig‘indisini hisoblash

package main

import "fmt"

func main() {
    sonlar := [5]int{4, 7, 2, 9, 3}
    yigindi := 0
    for _, son := range sonlar {
        yigindi += son
    }
    fmt.Println(yigindi)
}

Natija:

25

range indeks va qiymat qaytaradi. Bu misolda indeks kerak emasligi uchun uning o‘rniga bo‘sh identifikator _ yozilgan. Har bir qiymat yigindiga qo‘shiladi va dastur 25 sonini ekranga chiqaradi.

6. Eng katta element indeksini topish

package main

import "fmt"

func main() {
    sonlar := [5]int{4, 17, 8, 17, 3}
    engKatta := 0
    for i := 1; i < len(sonlar); i++ {
        if sonlar[i] > sonlar[engKatta] {
            engKatta = i
        }
    }
    fmt.Println(engKatta, sonlar[engKatta])
}

Natija:

1 17

engKatta o‘zgaruvchisi qiymatni emas, eng katta element indeksini saqlaydi. Dastlab 0-indeksdagi element eng katta deb olinadi. Sikl qolgan elementlarni sonlar[engKatta] qiymati bilan solishtiradi.

Taqqoslashda > ishlatilgan. Shu sabab eng katta qiymat bir necha marta uchrasa, uning birinchi indeksi saqlanadi. Bu massivda 17 ikki marta uchraydi, lekin natijada uning birinchi indeksi — 1 chiqadi.

7. Ikki o‘lchamli massiv

package main

import "fmt"

func main() {
    matritsa := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    for qator := range matritsa {
        for ustun := range matritsa[qator] {
            fmt.Print(matritsa[qator][ustun], " ")
        }
        fmt.Println()
    }
}

Natija:

1 2 3
4 5 6

[2][3]int — ikki qatorli va uch ustunli massiv. Har bir qatorning o‘zi uchta elementdan iborat [3]int massivi hisoblanadi. Elementni olish uchun avval qator, keyin ustun indeksi yoziladi: matritsa[qator][ustun].

8. Matritsaning bosh diagonali

package main

import "fmt"

func main() {
    matritsa := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
    yigindi := 0
    for i := range matritsa {
        yigindi += matritsa[i][i]
    }
    fmt.Println(yigindi)
}

Natija:

15

Bosh diagonaldagi elementlarning qator va ustun indekslari bir xil bo‘ladi: [0][0], [1][1] va [2][2]. Sikl 1, 5 va 9 qiymatlarini qo‘shadi. Shu sabab natija 15 bo‘ladi.

9. Raqamlar chastotasi

package main

import "fmt"

func main() {
    son := 120221
    var sanoq [10]int
    for son > 0 {
        sanoq[son%10]++
        son /= 10
    }
    fmt.Println(sanoq)
}

Natija:

[1 2 3 0 0 0 0 0 0 0]

Bu misolda massiv indeksi raqamning o‘zini bildiradi. Indeksdagi qiymat esa shu raqam necha marta uchraganini saqlaydi. Masalan, sanoq[2] qiymati 2 raqamining son ichida necha marta borligini ko‘rsatadi. 120221 sonida 1 ikki marta, 2 esa uch marta qatnashgan.

O‘nlik sanoq tizimida 0 dan 9 gacha doim o‘nta raqam bor. Elementlar soni o‘zgarmagani uchun bu vazifada [10]int massivi mos keladi.

Info

Ushbu sodda misolda son musbat deb olingan. Agar son qiymati aynan 0 bo‘lsa, sikl ishlamaydi va nol raqami sanalmaydi. Tashqi ma’lumot bilan ishlaydigan dasturda bu holatni alohida tekshirish kerak.

10. Massivni joyida teskari qilish

package main

import "fmt"

func main() {
    massiv := [5]int{10, 20, 30, 40, 50}
    for chap, ong := 0, len(massiv)-1; chap < ong; chap, ong = chap+1, ong-1 {
        massiv[chap], massiv[ong] = massiv[ong], massiv[chap]
    }
    fmt.Println(massiv)
}

Natija:

[50 40 30 20 10]

chap indeksi massiv boshidan, ong esa oxiridan yuradi. Har bir iteratsiyada shu indekslardagi qiymatlar o‘zaro almashtiriladi. Indekslar uchrashganda sikl tugaydi. O‘zgartirish massivning o‘zida bajarilgani uchun qo‘shimcha massiv kerak emas.

Keyingi darsda elementlar sonini o‘zgartirish mumkin bo‘lgan slice, uning uzunligi, sig‘imi va append() funksiyasi bilan ishlashni o‘rganamiz.