Перейти к содержанию

Мапы

TL;DR

  • map[K]V — hashmap, доступ O(1) amortized.
  • v, ok := m[k] — comma-ok idiom для проверки.
  • Итерация в случайном порядке.
  • nil map можно читать (вернёт zero value), писать в неё — panic.
  • Запись из нескольких горутин одновременно — fatal error.

Создание

m := map[string]int{"a": 1, "b": 2}
m := make(map[string]int)
m := make(map[string]int, 100)   // подсказка по capacity
var m map[string]int             // nil map, читать можно, писать нельзя

Comma-ok

v, ok := m["x"]
if !ok { /* ключа нет */ }

Без ok нельзя отличить «нет ключа» от «значение == zero».

Конкурентность

Map в Go не thread-safe. Несколько горутин одновременно пишут → fatal error: concurrent map writes.

Варианты:

// 1. Mutex
var m = struct{
    sync.RWMutex
    data map[string]int
}{data: map[string]int{}}

m.Lock()
m.data["a"] = 1
m.Unlock()

// 2. sync.Map — но только если ключи редко меняются и читателей сильно больше
var sm sync.Map
sm.Store("a", 1)
v, ok := sm.Load("a")

Когда sync.Map лучше: read-mostly, write-rare. В общем случае map + Mutex быстрее.

Гочча — нельзя взять адрес

m := map[string]int{"one": 1}
p := &m["one"]   // compile error

Map может быть переаллоцирован при росте → адреса нестабильны.

Гочча — итерация в случайном порядке

for k, v := range m {
    fmt.Println(k, v)  // порядок разный каждый запуск
}

Это сделано намеренно, чтобы код не полагался на порядок. Если порядок нужен — собери ключи в slice, отсортируй, итерируй по slice.

📖 Связанные задачи: must-solve-100 → C-005, C-011.