Зачем мне делать () или новый ()? - PullRequest
175 голосов
/ 17 февраля 2012

Во вводных документах много параграфов, в которых объясняется разница между new() и make(), но на практике вы можете создавать объекты в локальной области видимости и возвращать их.

Зачем использовать парураспределители?

Ответы [ 7 ]

142 голосов
/ 17 февраля 2012

Go имеет несколько способов выделения памяти и инициализации значения:

&T{...}, &someLocalVar, new, make

Распределение также может происходить при создании составных литералов.


new может использоваться для выделения значений, таких как целые числа, &int недопустимо:

new(Point)
&Point{}      // OK
&Point{2, 3}  // Combines allocation and initialization

new(int)
&int          // Illegal

// Works, but it is less convenient to write than new(int)
var i int
&i

Разницу между new и make можно увидеть, посмотрев на следующий пример:

p := new(chan int)   // p has type: *chan int
c := make(chan int)  // c has type: chan int

Предположим, что Go не имеет new и make, но имеет встроенную функцию NEW. Тогда пример кода будет выглядеть так:

p := NEW(*chan int)  // * is mandatory
c := NEW(chan int)

* будет обязательным , поэтому:

new(int)        -->  NEW(*int)
new(Point)      -->  NEW(*Point)
new(chan int)   -->  NEW(*chan int)
make([]int, 10) -->  NEW([]int, 10)

new(Point)  // Illegal
new(int)    // Illegal

Да, возможно объединение new и make в одну встроенную функцию. Тем не менее, вполне вероятно, что одна встроенная функция приведет к большей путанице среди новых программистов на Go, чем наличие двух встроенных функций.

Учитывая все вышеперечисленные пункты, представляется более целесообразным, чтобы new и make оставались отдельными.

141 голосов
/ 17 февраля 2012

Вещи, которые вы можете сделать с make, которые вы не можете сделать другим способом:

  • Создать канал
  • Создать карту с заранее выделенным пространством
  • Создать срез с заранее выделенным пространством или с len! = Cap

Это немного сложнее оправдать new. Главное, что делает это проще - это создание указателей на несоставные типы. Две функции ниже эквивалентны. Просто немного лаконичнее:

func newInt1() *int { return new(int) }

func newInt2() *int {
    var i int
    return &i
}
20 голосов
/ 01 сентября 2015

make-функция выделяет и инициализирует только объекты типа slice, map или chan.Как новый, первый аргумент является типом.Но он также может принимать второй аргумент, размер.В отличие от new, тип возвращаемого значения make совпадает с типом аргумента, а не с указателем на него.И выделенное значение инициализируется (не устанавливается в нулевое значение, как в новом). Причина в том, что слайс, карта и канал являются структурами данных.Их нужно инициализировать, иначе их нельзя будет использовать. По этой причине new () и make () должны отличаться.

Следующие примеры из Effective Go проясняют это:

p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable
8 голосов
/ 17 февраля 2012

Помимо всего того, что объясняется в Effective Go , основное отличие между new(T) и &T{} заключается в том, что последний явно выполняет выделение кучи. Однако следует отметить, что это зависит от реализации и, следовательно, может быть изменено.

Сравнение make с new не имеет особого смысла, так как они выполняют совершенно разные функции. Но это подробно объясняется в связанной статье.

6 голосов
/ 17 февраля 2012

Вам нужно make() для создания каналов и карт (и фрагментов, но они также могут быть созданы из массивов).Нет альтернативного способа сделать это, поэтому вы не можете удалить make() из своего лексикона.

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

4 голосов
/ 05 апреля 2019
  • new(T) - выделяет память и устанавливает ее на нулевое значение для типа T ..
    .. это 0 для int , "" для string и nil для ссылочных типов ( slice , map чан )

    Обратите внимание, что ссылочные типы являются просто указателями на некоторые базовые структуры данных , которые не будут созданы к new(T)
    Пример: в случае slice базовый массив не будет создан, таким образом, new([]int) возвращает указатель на ничто

  • make(T) - выделяет память для ссылочных типов данных ( слайс , карта , chan ), плюс инициализирует их базовые структуры данных

    Пример: в случае слайс будет создан базовый массив с указанной длиной и емкостью
    Помните, что, в отличие от C, массив в Go является примитивным типом!


Как говорится:

make(T) ведет себя как составной-буквальный синтаксис new(T) ведет себя как var (когда переменная не инициализирована)
func main() {
    fmt.Println("-- MAKE --")
    a := make([]int, 0)
    aPtr := &a
    fmt.Println("pointer == nil :", *aPtr == nil)
    fmt.Printf("pointer value: %p\n\n", *aPtr)

    fmt.Println("-- COMPOSITE LITERAL --")
    b := []int{}
    bPtr := &b
    fmt.Println("pointer == nil :", *bPtr == nil)
    fmt.Printf("pointer value: %p\n\n", *bPtr)

    fmt.Println("-- NEW --")
    cPtr := new([]int)
    fmt.Println("pointer == nil :", *cPtr == nil)
    fmt.Printf("pointer value: %p\n\n", *cPtr)

    fmt.Println("-- VAR (not initialized) --")
    var d []int
    dPtr := &d
    fmt.Println("pointer == nil :", *dPtr == nil)
    fmt.Printf("pointer value: %p\n", *dPtr)
}

Запустите программу

-- MAKE --
pointer == nil : false
pointer value: 0x118eff0  # address to underlying array

-- COMPOSITE LITERAL --
pointer == nil : false
pointer value: 0x118eff0  # address to underlying array

-- NEW --
pointer == nil : true
pointer value: 0x0

-- VAR (not initialized) --
pointer == nil : true
pointer value: 0x0

Дополнительное чтение:
https://golang.org/doc/effective_go.html#allocation_new https://golang.org/doc/effective_go.html#allocation_make

4 голосов
/ 19 ноября 2017

new (T): возвращает указатель на тип T значение типа * T, выделяет и обнуляет память. new (T) эквивалентно & T {} .

make (T): оно возвращает инициализированное значение типа T , выделяет и инициализирует память.Используется для фрагментов, карты и каналов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...