Коллекции: массивы, срезы и отображения

Map: создание, чтение, запись, удаление и проверка ключа

Содержание курса

Обход map через range и неопределённость порядка итерации

Синтаксис range для map выглядит так же, как для среза, который вы уже использовали:

m := map[string]int{"alice": 3, "bob": 1, "carol": 7}

for k, v := range m {
    fmt.Println(k, v)
}

Но есть принципиальное отличие от среза: спецификация Go не задаёт порядок обхода map и не гарантирует, что два последовательных обхода дадут одинаковую последовательность пар. Два прогона могут дать как одинаковый, так и разный порядок — полагаться на него нельзя в любом случае.

Если нужен только ключ:

for k := range m {
    fmt.Println(k)
}

Если нужно только значение:

for _, v := range m {
    fmt.Println(v)
}

Пустой идентификатор _ работает здесь так же, как и в range по срезу — отбрасывает переменную, которая не нужна.

Практическое следствие: тест, который проверяет порядок строк в выводе, построенном по range по map, ненадёжен и потенциально нестабилен — даже если на конкретной машине он проходит несколько раз подряд. Корректный тест проверяет наличие нужных ключей и значений в map, а не порядок их перечисления.