range per map — tvarka ATSITIKTINĖ
Kad aplankytum kiekvieną įrašą, naudok range — tas pats žodis kaip su sąrašais, bet gauni raktą ir reikšmę:
counts := map[string]int{"istorija": 2, "mokslas": 5, "poezija": 1}
for kategorija, n := range counts {
fmt.Printf("%s: %d\n", kategorija, n)
}
(Tas map[string]int{...} — map literalas, greitas būdas iš karto sukurti užpildytą žodyną.)
Dabar spąstai — ir mes juos įrodysim, o ne tik pareikšim. Pereik per tą patį žodyną du kartus vienoje programoje:
func main() {
counts := map[string]int{
"fantasy": 3, "history": 2, "science": 5,
"poetry": 1, "biography": 4, "travel": 2,
}
fmt.Print("Pass 1:")
for k := range counts {
fmt.Print(" ", k)
}
fmt.Println()
fmt.Print("Pass 2:")
for k := range counts {
fmt.Print(" ", k)
}
fmt.Println()
}
Paleisk. Štai tikras paleidimas:
Pass 1: fantasy history science poetry biography travel
Pass 2: science poetry biography travel fantasy history
Įsižiūrėk: Pass 1 ir Pass 2 skiriasi — toje pačioje programoje, tame pačiame žodyne, nieko tarp jų nepakeitus. Paleisk programą dar kartą — abi eilutės išeis vėl kita tvarka. Tvarka nėra nei abėcėlinė, nei įrašymo, nei jokia, kurią galėtum nuspėti.
Kodėl Go tai daro sąmoningai? Nes map yra maišos lentelė (hash table) — ji neturi savaiminės tvarkos. Anksti Go turėjo atsitiktinai stabilią tvarką, ir žmonės pradėjo ja pasikliauti („pirmas raktas visada X"). Toks kodas lūždavo vos žodynui paaugus ir Go pertvarkius savo „kibirus" (buckets). Todėl Go dabar atsitiktinai parenka kiekvieno range pradžios tašką — tyčia — kad niekas nesiremtų tvarka, kurios niekada nebuvo žadėta. Tai privalumas: paverčia „veikia mano kompiuteryje" klaidą tokia, kuri išlenda per patį pirmą paleidimą.
Ką tai reiškia tau:
- Niekada nesiremk map tvarka.
for k := range mkaskart duoda raktus atsitiktine tvarka. - Naudok map, kai ieškai pagal raktą arba skaičiuoji/grupuoji — įrašų tvarka nesvarbi.
- Kai reikia fiksuotos tvarkos (pvz., spausdinti kategorijas abėcėliškai), surink raktus į sąrašą ir jį surūšiuok. Rūšiavimas — Algoritmų kurso darbas; kol kas tiesiog žinok, kad pats map to nepadarys.
Spąstai (testas, kuris šiandien praeina, o penktadienį krenta). Jei parašysi testą, tikintį map išvesties konkrečia tvarka, jis kartais praeis, kartais kris — klasikinis nepatikimas testas (flaky test). Sprendimas niekada nėra „paleisk dar kartą"; jis — nustoti remtis tvarka (lygink skaičius, ne atspausdintą eilutę). Įsidėmėk — automatinius testus sutiksim 13 pamokoje.
Toliau: pritaikom map TAVO programoje — skaičiuojam įrašus pagal kategoriją ir randam vieną akimirksniu pagal pavadinimą.