ПрограммированиеGo разработчик

Объясните особенности работы встроенной функции make в Go: когда она необходима, как работает срезание инициализации для map, slice и channel? Какие ошибки встречаются из-за неправильного использования make и new?

Проходите собеседования с ИИ помощником Hintsage

Ответ

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

Примеры:

s := make([]int, 5, 10) // срез длиной 5, ёмкостью 10 m := make(map[string]int) // пустая мапа ch := make(chan int, 2) // буферизованный канал на 2

Тонкости:

  • Для slice параметры: длина (len) и (необязательно) ёмкость (cap).
  • Для map и chan — только (необязательная) ёмкость (начальный размер/буфер).
  • Функция make возвращает уже инициализированный объект, готовый к использованию.
  • Для других типов (struct, array) make не используется, их инициализируют с помощью литералов или new (которая возвращает указатель на zero value).

Сравнение с new:

  • new(T) возвращает *T, где все поля нулевые.
  • make(T) возвращает T только для трех типов: slice, map, chan.

Вопрос с подвохом

Можно ли получить рабочий map через new вместо make?

m := new(map[string]int) (*m)["a"] = 1 // Что произойдет?

Многие считают, что это корректно, но возникнет panic в runtime: assignment to entry in nil map. Потому что в переменной *m лежит nil!

Правильно: использовать make:

m := make(map[string]int) m["a"] = 1 // OK

Примеры реальных ошибок из-за незнания тонкостей темы


История

В микросервисе для хранения кэша создавали map через var cache map[string]interface{} без инициализации make, из-за чего при записи возникал panic в production с непонятными stack trace. Проблема нашлась только после анализа кода: map была nil.


История

При написании конвейера данных забыли про буфер у канала и создали через make(chan int). В результате, горутины застревали, дожидаясь чтения, хотя ожидался асинхронный обмен. Ошибку заметили только при масштабном тесте.


История

В проекте, где инициализация шла через new, некоторые разработчики пытались использовать new([]int) вместо make([]int, 10), в итоге получали указатель на nil slice и runtime-панику при первых попытках записи.