Зачем мне делать() или new()?

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

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

Ответ 1

Что вы можете сделать с make, что вы не можете сделать иначе:

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

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

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

func newInt2() *int {
    var i int
    return &i
}

Ответ 2

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 остается отдельный.

Ответ 3

Функция

make выделяет и инициализирует только объект типа slice, map или chan. Как новый, первым аргументом является тип. Но, он также может принять второй аргумент - размер. В отличие от нового, тип возвращаемого значения аналогичен типу его аргумента, а не указателю на него. И выделенное значение инициализируется (не устанавливается на нулевое значение, как в новом). Причина в том, что срез, карта и чан являются структурами данных. Они должны быть инициализированы, иначе они не будут использоваться. Это причина, по которой 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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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


Что, как говорится:

make(T) ведет себя как составной-буквальный синтаксис new() ведет себя как 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