Функция 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 возвращает уже инициализированный объект, готовый к использованию.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-панику при первых попытках записи.