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

Что возвращает Make?

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

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

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

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

Краткий ответ

Функция make() в Go возвращает инициализированный (не нулевой) экземпляр одного из трёх встроенных типов: слайс (slice), карту (map) или канал (channel). В отличие от new(), которая возвращает указатель на нулевое значение типа, make() выполняет дополнительную инициализацию внутренних структур данных, необходимую для их корректной работы.

Подробное объяснение

Назначение и синтаксис

make() — это встроенная функция, используемая для создания и инициализации сложных встроенных типов, которые требуют подготовки внутренних структур перед использованием. Синтаксис зависит от типа:

// Для слайса
slice := make([]T, len, cap) // cap (ёмкость) опциональна

// Для карты
map := make(map[K]V, initialCapacity) // initialCapacity опциональна

// Для канала
ch := make(chan T, bufferSize) // bufferSize опциональна

Что именно возвращается для каждого типа

1. Для слайса (slice)

make() возвращает инициализированный слайс с заданной длиной и ёмкостью. Под капотом выделяется массив заданной ёмкости, и слайс получает на него ссылку.

// Создаёт слайс с длиной 5 и ёмкостью 10
s := make([]int, 5, 10)
fmt.Println(len(s)) // 5
fmt.Println(cap(s)) // 10
fmt.Println(s)      // [0 0 0 0 0] - все элементы нулевые

Важно: Элементы слайса инициализируются нулевыми значениями типа (для int — 0). Если ёмкость не указана, она равна длине.

2. Для карты (map)

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

// Создаёт карту с начальной ёмкостью ~100
m := make(map[string]int, 100)
m["key"] = 42 // Можно сразу использовать

Без make() карта имеет значение nil, и попытка записи вызовет панику.

3. Для канала (channel)

make() возвращает инициализированный канал с указанным типом данных и буфером (если задан).

// Буферизированный канал на 10 элементов
ch := make(chan string, 10)
// Небуферизированный канал
ch2 := make(chan struct{})

Ключевые отличия от new()

  • new(T) возвращает *T (указатель на нулевое значение типа T)
  • make(T, args...) возвращает T (само инициализированное значение, не указатель)
// new() — не подходит для слайсов, карт и каналов
p := new([]int)   // p имеет тип *[]int, *p == nil (нулевой слайс)
p = make([]int, 5) // ОШИБКА: make нельзя использовать как выражение присваивания

// Правильно:
var slice []int = make([]int, 5) // Возвращает []int
m := make(map[string]int)        // Возвращает map[string]int
ch := make(chan bool)            // Возвращает chan bool

Внутренняя инициализация

make() не просто выделяет память — она выполняет специфичную для типа подготовку:

  • Для слайса: создаёт базовый массив и структуру слайса (указатель, длину, ёмкость)
  • Для карты: инициализирует хеш-таблицу, корзины (buckets)
  • Для канала: создаёт буфер (при необходимости) и структуры синхронизации (mutex, очереди горутин)

Практические примеры использования

// 1. Слайс с предопределённым размером
ids := make([]int64, 0, 1000) // Оптимизация: сразу выделяем память для 1000 элементов

// 2. Карта для подсчёта частот
freq := make(map[rune]int)
for _, ch := range "hello" {
    freq[ch]++
}

// 3. Канал для связи горутин
done := make(chan struct{})
go func() {
    // работа...
    done <- struct{}{}
}()

Итог

Функция make() возвращает готовый к использованию экземпляр слайса, карты или канала, выполняя всю необходимую внутреннюю инициализацию. Это единственный корректный способ создания этих типов (кроме литералов для слайсов и карт), поскольку простого выделения памяти недостаточно — требуется настройка внутренних структур данных.