Для чего нужна встроенная функция make() и чем она отличается от new()?

Ответ

Функция make() — это встроенная функция в Go, предназначенная исключительно для инициализации трёх встроенных ссылочных типов: срезов (slices), карт (maps) и каналов (channels).

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

Синтаксис:

  • Срезы: make([]T, length, capacity) — создаёт срез с указанной длиной и ёмкостью.
  • Карты: make(map[K]V, initialCapacity) — создаёт карту с предварительно выделенной памятью для initialCapacity элементов, что помогает избежать лишних аллокаций при росте карты.
  • Каналы: make(chan T, bufferSize) — создаёт канал. Если bufferSize > 0, канал будет буферизированным.

Пример:

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

// Создаем карту для хранения пар string:int
m := make(map[string]int)
m["age"] = 30

// Создаем буферизированный канал на 3 элемента
ch := make(chan int, 3)

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

Это частый вопрос на собеседованиях, и разница принципиальна:

Характеристикаmake(T)new(T)
НазначениеИнициализирует срезы, карты и каналыВыделяет память для любого типа и обнуляет её
Возвращаемое значениеВозвращает значение типа T (например, []int)Возвращает указатель на значение *T (например, *int)
РезультатГотовый к использованию, инициализированный объектУказатель на нулевое значение типа T

Простой пример для понимания:

// new возвращает указатель на нулевое значение int (т.е. на 0)
var p_int *int = new(int)
fmt.Println(*p_int) // 0

// make возвращает готовую к использованию карту
var m map[string]int = make(map[string]int)
m["test"] = 1 // Работает!

// А так было бы с new - паника!
// var m_new *map[string]int = new(map[string]int)
// (*m_new)["test"] = 1 // panic: assignment to entry in nil map

Использование new(map[string]int) создаст указатель на nil-карту, в которую нельзя записывать данные без дополнительной инициализации через make().