← Назад к вопросам

Есть ли у map cap?

1.3 Junior🔥 82 комментариев
#Основы Go

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличие cap() от len() и специфика map в Go

Нет, у map в Go нет capacity (ёмкости), в отличие от slice и channel. Функция cap() возвращает ёмкость только для слайсов (текущий размер внутреннего массива) и каналов (размер буфера), но при попытке применить её к map возникает ошибка компиляции.

Пример, демонстрирующий ошибку

package main

import "fmt"

func main() {
    m := make(map[string]int)
    fmt.Println(len(m)) // Работает, выведет 0
    
    // fmt.Println(cap(m)) // Ошибка компиляции: invalid argument m (type map[string]int) for cap
}

Почему у map нет capacity?

Принципиальные различия в устройстве данных объясняют это:

  • Слайс — это абстракция над непрерывным массивом. Ёмкость (capacity) показывает, сколько элементов можно добавить до переаллокации и копирования данных в новый, больший массив. Это важно для оптимизации производительности при постепенном заполнении.
  • Map (хэш-таблица) — имеет гораздо более сложную внутреннюю структуру. В стандартной реализации Go (runtime/map.go) она состоит из "бакетов" (buckets), каждый из которых содержит несколько пар ключ-значение. Процесс роста map нелинеен и детерминирован внутренними алгоритмами.

Как задать начальный размер map?

Хотя cap() неприменима, вы можете указать примерный начальный размер (hint) при создании map с помощью make(). Это не гарантированная ёмкость, а лишь подсказка рантайму, чтобы он выделил достаточное количество начальных бакетов и минимизировал переаллокации при последующем заполнении.

package main

import "fmt"

func main() {
    // Создаём map с подсказкой, что в неё планируется добавить ~1000 элементов
    m := make(map[string]int, 1000)
    
    // При добавлении первых 1000 элементов переаллокаций (дорогих операций) скорее всего не будет.
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key_%d", i)
        m[key] = i
    }
    
    fmt.Println("Добавлено элементов:", len(m))
}

Ключевые выводы

  • cap() не работает с map — это ошибка компиляции.
  • len() для map возвращает текущее количество пар ключ-значение.
  • Hint в make() — это способ указать ожидаемый размер при создании map для повышения производительности. Рантайм округляет это число для создания необходимого количества начальных бакетов.
  • Сложность внутренней структуры — map реализована как хэш-таблица с бакетами, и её рост управляется внутренней логикой, скрытой от пользователя.

Если вам критически важно управлять производительностью map при заполнении, лучшая практика — заранее выделять её с помощью make(map[K]V, expectedSize), где expectedSize — это ваша оценка будущего количества элементов. Это позволяет избежать множественных переаллокаций на старте.