Во вводных документах много абзацев, посвященных объяснению различий между new()
и make()
, но на практике вы можете создавать объекты в локальной области и возвращать их.
Зачем вам использовать пару распределителей?
То, что вы можете сделать с make
этим, вы не можете сделать по-другому:
Это немного сложнее оправдать new
. Главное, что делает это проще - это создание указателей на несоставные типы. Две функции ниже эквивалентны. Просто немного более кратко:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}
вместоm := make(map[string]int)
? нет необходимости предварительно выделять размер.Go имеет несколько способов выделения памяти и инициализации значения:
&T{...}
,&someLocalVar
,new
,make
Выделение также может происходить при создании составных литералов.
new
может использоваться для выделения значений, таких как целые числа,&int
недопустимо:Разницу между
new
иmake
можно увидеть, посмотрев на следующий пример:Предположим, что Go не имеет
new
иmake
, но имеет встроенную функциюNEW
. Тогда пример кода будет выглядеть так:Это
*
будет обязательно , так что:Да, слияние
new
иmake
в единую встроенную функцию. Тем не менее, вполне вероятно, что одна встроенная функция приведет к большей путанице среди новых программистов Go, чем наличие двух встроенных функций.Учитывая все вышеперечисленные моменты, представляется более уместным
new
иmake
остается отдельным.источник
int
он создается.make(Point)
иmake(int)
в этих последних двух строках?make
Функция выделяет и инициализирует объект типа slice, map или chan only. Молnew
, первый аргумент - это тип. Но он также может принимать второй аргумент, размер. В отличие от new, возвращаемый тип make совпадает с типом аргумента, а не с указателем на него. И выделенное значение инициализируется (не устанавливается в нулевое значение, как в новом). Причина в том, что слайс, карта и канал являются структурами данных. Их нужно инициализировать, иначе их нельзя будет использовать.Это причина, по которой new () и make () должны отличаться.Следующие примеры из Effective Go проясняют это:
источник
new([]int)
, он просто выделяет память для [] int, но не инициализирует, поэтому он просто возвращаетnil
; не указатель на память, потому что он непригоден для использования.make([]int)
выделяет и инициализирует, чтобы его можно было использовать, затем возвращает его адрес.new(T)
- Распределяет память и устанавливает ее в нулевое значение для типа T ....это
0
для int ,""
для строки иnil
для ссылочных типов ( slice , map , chan )Обратите внимание, что ссылочные типы - это просто указатели на некоторые базовые структуры данных , которые не будут созданы в
new(T)
примере: в случае слайса базовый массив не будет создан, поэтому он
new([]int)
возвращает указатель на ничтоmake(T)
- выделяет память для ссылочных типов данных ( срез , карта , канал ), а также инициализирует их базовые структуры данныхПример: в случае среза базовый массив будет создан с заданной длиной и емкостью.
Помните, что, в отличие от C, массив является примитивным типом в Go!
Что, как говорится:
make(T)
ведет себя как составной-буквальный синтаксисnew(T)
ведет себя какvar
(когда переменная не инициализирована)Запустите программу
Дополнительная информация:
https://golang.org/doc/effective_go.html#allocation_new. https://golang.org/doc/effective_go.html#allocation_make.
источник
Вам нужно
make()
создавать каналы и карты (и фрагменты, но они также могут быть созданы из массивов). Там нет альтернативного способа сделать это, поэтому вы не можете удалитьmake()
из своего лексикона.Что касается
new()
, я не знаю ни одной причины, почему она вам нужна, когда вы можете использовать структурный синтаксис. Тем не менее, он имеет уникальное семантическое значение: «создать и вернуть структуру со всеми полями, инициализированными до их нулевого значения», что может быть полезно.источник
Помимо всего, что объясняется в Effective Go , основное различие между
new(T)
и&T{}
заключается в том, что последний явно выполняет выделение кучи. Однако следует отметить, что это зависит от реализации и, следовательно, может быть изменено.Сравнивать
make
с неnew
имеет смысла, поскольку эти два выполняют совершенно разные функции. Но это подробно объясняется в связанной статье.источник
&T{}
явно выполняет распределение кучи, является AFAIK, не основанным ни на чем в спецификациях. На самом деле, я считаю, что анализ escape уже хранит такие * T в стеке, когда это возможно, точно так же, как и сnew(T)
.new (T): он возвращает указатель на тип T значение типа * T, он выделяет и обнуляет память. new (T) эквивалентно & T {} .
make (T): возвращает инициализированное значение типа T , выделяет и инициализирует память. Его используют для срезов, карты и каналов.
источник