В чем разница между `new()` и `make()` в Go?

Ответ

new и make — это две встроенные функции в Go для выделения памяти, но они работают по-разному и для разных целей.

new(T)

  1. Что делает: Выделяет память для значения типа T, инициализирует её нулевым значением этого типа.
  2. Что возвращает: Возвращает указатель на эту память (*T).
  3. Для каких типов: Может использоваться для любого типа данных (числа, структуры, массивы и т.д.).
// p - это указатель на int (*int), 
// а значение по этому указателю равно 0.
p := new(int)
fmt.Println(*p) // Выведет: 0

// user - это указатель на структуру (*User),
// все поля которой (ID, Name) имеют нулевые значения (0, "").
type User struct {
    ID   int
    Name string
}
user := new(User)
fmt.Printf("%+vn", *user) // Выведет: {ID:0 Name:}

make(T, size...)

  1. Что делает: Создаёт и инициализирует готовый к использованию объект.
  2. Что возвращает: Возвращает инициализированное значение типа T (не указатель!).
  3. Для каких типов: Используется только для трёх встроенных ссылочных типов: slice, map и chan.

Причина в том, что эти типы являются дескрипторами, которые ссылаются на внутренние структуры данных. make не только выделяет память под сам дескриптор, но и под его внутреннюю структуру, делая объект пригодным к использованию.

// s - это срез с длиной 5 и ёмкостью 5.
// Он готов к записи элементов по индексам.
s := make([]int, 5)
s[0] = 100

// m - это готовая к использованию пустая карта.
m := make(map[string]int)
m["age"] = 30

// ch - это буферизированный канал на 1 элемент.
ch := make(chan bool, 1)

Итог

new(T)make(T)
НазначениеВыделение памяти и обнулениеСоздание и инициализация
Возвращаемый типУказатель (*T)Значение (T)
ПрименимостьЛюбой типТолько slice, map, chan