Tarkibga o'tish

Go’da map ma’lumot turi

map kalit-qiymat juftlarini saqlaydi. Slice’da element indeks orqali topilsa, mapda unga mazmunli kalit orqali murojaat qilinadi. Masalan, mahsulot narxini kodi orqali yoki foydalanuvchini ID orqali topish mumkin.

Bitta mapdagi barcha kalitlar bir xil turda, barcha qiymatlar ham bir xil turda bo‘ladi. Har bir kalit yagona, lekin turli kalitlar bir xil qiymatga ega bo‘lishi mumkin.

map yaratish

map[KalitTuri]QiymatTuri turini literal yoki make bilan yaratish mumkin:

package main

import "fmt"

func main() {
    narxlar := map[string]int{
        "non":  4_000,
        "sut":  12_000,
        "guruch": 18_000,
    }

    ombor := make(map[string]int)
    ombor["non"] = 25

    fmt.Println("Sut narxi:", narxlar["sut"])
    fmt.Println("Non miqdori:", ombor["non"])
}

Natija:

Sut narxi: 12000
Non miqdori: 25

make(map[string]int) yozishga tayyor bo‘sh map qaytaradi. makega taxminiy elementlar sonini berish ham mumkin: make(map[string]int, 100). Bu uzunlikni belgilamaydi, faqat oldindan joy tayyorlashga yordam berishi mumkin.

nil va bo‘sh map

mapning nol qiymati nil:

package main

import "fmt"

func main() {
    var nilMap map[string]int
    boshMap := make(map[string]int)

    fmt.Println(len(nilMap), nilMap == nil)
    fmt.Println(len(boshMap), boshMap == nil)
    fmt.Println(nilMap["yo‘q"])
}

Natija:

0 true
0 false
0

nil map’dan o‘qish, uning uzunligini olish, u bo‘ylab yurish va delete qilish xavfsiz. Ammo unga qiymat yozish panic: assignment to entry in nil map xatosini beradi. Yozishdan oldin literal yoki make bilan tayyorlang.

Kalit mavjudligini tekshirish

Mavjud bo‘lmagan kalit o‘qilsa, qiymat turining nol qiymati qaytadi. Bu kalit yo‘qligini har doim ham bildirmaydi, chunki nol qiymat ataylab saqlangan bo‘lishi mumkin. “Vergul, ok” (comma ok) shakli bu ikki holatni ajratadi:

package main

import "fmt"

func main() {
    ballar := map[string]int{"Ali": 0}

    ball, bor := ballar["Ali"]
    fmt.Println("Ali:", ball, bor)

    ball, bor = ballar["Vali"]
    fmt.Println("Vali:", ball, bor)
}

Natija:

Ali: 0 true
Vali: 0 false

Qiymat kerak bo‘lmasa, _, bor := ballar["Ali"] deb yoziladi.

Qiymatni yangilash va o‘chirish

Mavjud kalitga qayta qiymat berish eski qiymatni almashtiradi. delete kalitni o‘chiradi; kalit mavjud bo‘lmasa ham xato bermaydi.

package main

import "fmt"

func main() {
    foydalanuvchi := map[string]string{"ism": "Sardor", "shahar": "Toshkent"}
    foydalanuvchi["ism"] = "Elbek"
    delete(foydalanuvchi, "shahar")

    fmt.Println(foydalanuvchi["ism"])
    _, bor := foydalanuvchi["shahar"]
    fmt.Println("Shahar mavjud:", bor)
}

Natija:

Elbek
Shahar mavjud: false

Qaysi turlar kalit bo‘la oladi?

Kalit turi == va != bilan taqqoslanadigan bo‘lishi kerak. Son, satr, bool, pointer, channel, interface hamda faqat taqqoslanadigan maydonlardan iborat array va struct kalit bo‘la oladi. Slice, map va funksiya kalit bo‘la olmaydi.

type Koordinata struct {
    X int
    Y int
}

var kataklar map[Koordinata]string

float64 texnik jihatdan kalit bo‘la oladi, ammo NaN o‘ziga ham teng emas. Amaliy kodda kasrli sonni kalit qilishdan ehtiyot bo‘ling.

range va tartib

map bo‘ylab yurish tartibi kafolatlanmagan:

package main

import (
    "fmt"
    "sort"
)

func main() {
    yoshlar := map[string]int{"Ali": 24, "Vali": 31, "Lola": 27}
    kalitlar := make([]string, 0, len(yoshlar))

    for ism := range yoshlar {
        kalitlar = append(kalitlar, ism)
    }
    sort.Strings(kalitlar)

    for _, ism := range kalitlar {
        fmt.Println(ism, yoshlar[ism])
    }
}

Natija:

Ali 24
Lola 27
Vali 31

Barqaror chiqish kerak bo‘lsa, kalitlarni slice’ga yig‘ib saralang. Testlar, loglar va foydalanuvchiga ko‘rsatiladigan ro‘yxatlarda tasodifiy tartibga tayanmang.

Tayinlash, funksiyaga uzatish va parallel ishlash

b := a barcha elementlarni chuqur nusxalamaydi. a va b bir xil asosiy map ma’lumotiga murojaat qiladi; biri orqali o‘zgarish ikkinchisida ko‘rinadi. Mustaqil nusxa kerak bo‘lsa, yangi map yaratib juftlarni ko‘chiring.

Oddiy map bir vaqtda bir nechta goroutine tomonidan yozish uchun xavfsiz emas. Parallel kirishda sync.Mutex, sync.RWMutex, kanal orqali egalik yoki vazifaga mos bo‘lsa sync.Map kabi sinxronlash kerak. Bu mavzu concurrency darslarida batafsil o‘rganiladi.

Xulosa

  • map qiymatni yagona kalit orqali topadi.
  • Mavjud bo‘lmagan kalit nol qiymat qaytaradi; mavjudlikni value, ok := m[key] bilan tekshiring.
  • nil map’dan o‘qish mumkin, yozish mumkin emas.
  • Iteratsiya tartibi kafolatlanmaydi.
  • map tayinlanganda elementlar chuqur nusxalanmaydi va parallel yozish alohida himoya talab qiladi.

Keyingi darsda qiymatning xotira manzilini saqlaydigan ko‘rsatkichlar ko‘rib chiqiladi.