Что такое `map` в Go, каковы его основные характеристики и ограничения?

Ответ

map в Go — это встроенный тип данных, который представляет собой неупорядоченную коллекцию пар "ключ-значение".

Основные характеристики:

  • Неупорядоченность: Порядок итерации по элементам map не гарантирован и может меняться от запуска к запуску. Нельзя полагаться на порядок элементов.
  • Динамический размер: map автоматически растет по мере добавления новых элементов.
  • Типы ключей: Ключом может быть любой тип данных, для которого определена операция сравнения (== и !=), например: string, int, float, указатели, структуры (если все их поля сравнимы).
  • Нулевое значение: Нулевое значение для map — это nil. Попытка записи в nil-мапу вызовет панику. Чтение из nil-мапы безопасно и всегда возвращает нулевое значение для типа значения.
  • Создание: Создается с помощью функции make(map[KeyType]ValueType) или через литерал map[KeyType]ValueType{}.

Важнейшее ограничение: Потокобезопасность

Стандартные map в Go не являются потокобезопасными. Одновременное чтение и запись (или две записи) из разных горутин без дополнительной синхронизации приведет к состоянию гонки (race condition) и непредсказуемому поведению. Для конкурентного доступа необходимо использовать мьютекс (sync.RWMutex) или специализированный тип sync.Map.

Пример использования:

package main

import "fmt"

func main() {
    // Создание и инициализация
    users := make(map[int]string)

    // Запись значений
    users[1] = "Alice"
    users[2] = "Bob"

    // Чтение и проверка наличия ключа (идиома "comma ok")
    if name, ok := users[1]; ok {
        fmt.Printf("Пользователь с ID 1: %sn", name) // Пользователь с ID 1: Alice
    }

    // Удаление элемента
    delete(users, 2)

    // Итерация (порядок не гарантирован)
    for id, name := range users {
        fmt.Printf("ID: %d, Name: %sn", id, name)
    }
}