Урок 3~12 минут
map
Что такое map
map — хеш-таблица: хранит пары ключ→значение. Ключом может быть любой comparable тип (числа, строки, структуры без слайсов). Значением — что угодно.
Создание
go
// make — предпочтительный способ
ages := make(map[string]int)
// Литерал с начальными значениями
capitals := map[string]string{
"Россия": "Москва",
"Германия": "Берлин",
"Япония": "Токио",
}
// nil-map — нельзя писать!
var m map[string]int
m["key"] = 1 // panic: assignment to entry in nil mapЗапись и чтение
go
ages := make(map[string]int)
// Запись
ages["Алиса"] = 30
ages["Боб"] = 25
// Чтение
fmt.Println(ages["Алиса"]) // 30
fmt.Println(ages["Карл"]) // 0 — ключа нет, но паники нетComma-ok паттерн
Чтобы отличить «ключ со значением 0» от «ключа нет»:
go
age, ok := ages["Карл"]
if !ok {
fmt.Println("Карл не найден")
} else {
fmt.Printf("Карлу %d лет\n", age)
}Короткий вариант:
go
if age, ok := ages["Алиса"]; ok {
fmt.Printf("Алисе %d лет\n", age)
}Удаление
go
delete(ages, "Боб")
fmt.Println(len(ages)) // уменьшился на 1delete безопасен — не паникует если ключа нет.
Итерация
go
for name, age := range ages {
fmt.Printf("%s: %d\n", name, age)
}Порядок не гарантирован — каждый раз разный. Для сортировки:
go
keys := make([]string, 0, len(ages))
for k := range ages {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s: %d\n", k, ages[k])
}Вложенные map
go
graph := map[string][]string{
"A": {"B", "C"},
"B": {"D"},
"C": {"D", "E"},
}
fmt.Println(graph["A"]) // [B C]Или map of maps:
go
matrix := map[int]map[int]int{}
matrix[0] = map[int]int{0: 1, 1: 2}
matrix[1] = map[int]int{0: 3, 1: 4}Частые паттерны
Счётчик:
go
words := strings.Fields("go is great go is fast")
count := make(map[string]int)
for _, w := range words {
count[w]++
}
// count["go"] = 2, count["is"] = 2, ...Множество (set):
go
seen := make(map[string]struct{})
seen["alice"] = struct{}{}
if _, ok := seen["alice"]; ok {
fmt.Println("уже видели")
}struct{} занимает 0 байт — идеально для множеств.
Конкурентный доступ
map не потокобезопасна. Одновременное чтение+запись из разных горутин вызовет панику. Решения:
go
// sync.Mutex
var mu sync.Mutex
mu.Lock()
m[key] = value
mu.Unlock()
// sync.Map — для read-heavy сценариев
var sm sync.Map
sm.Store("key", 42)
v, _ := sm.Load("key")Всегда проверяй второй return при чтении из map: v, ok := m[key]. Если ключа нет — вернётся нулевое значение, и ты не узнаешь об этом без ok.
| Ключ | Значение | |
|---|---|---|
| "alice" | 30 | |
| "bob" | 25 | |
| "carol" | 28 |
Живой код:
m := map[string]int{
"alice": 30,
"bob": 25,
"carol": 28,
}
// Добавить / обновить
m["diana"] = 22
// Удалить
delete(m, "bob")
// Найти (comma-ok)
val, ok := m["alice"]
// val=30, ok=true
🎯
Миссия 1 из 4
Как создать map с ключами string и значениями int?