2016-07-23 3 views
0

В чем отличие новой функции и неинициализированной переменной? В чем преимущество обоих?Разница в новой функции и неинициализированной переменной

s := new(string) // *string 
var s *string // *string 
var s string  // string 

Это только для простоты кода? Потому что я думаю, что это же

s := new(string) /* same as */ var s *string = &emptyString 
+0

новые выделяет память динамически, для неинициализированной переменной памяти еще не выделен. – ShivBuyya

+0

Это адрес памяти или содержимого памяти? потому что, если я проверяю адрес обоих, они выделяются. Содержание также. –

ответ

2

первое отличие:

Встроенная функция нового принимает тип Т, выделяет память для переменной этого типа во время выполнения

2 разница: new инициализирует выделенную строку пустой строкой ("") и инициализирует указатель на a ddress этой строки, но var ptr2 *string просто инициализирует ptr2 к nil и не выделяет любую строку:

образец кода A (с комментариями выход):

ptr := new(string)    // *ptr has value "", ptr: static type *string 
fmt.Println(len(*ptr))   // 0 
fmt.Println(cap([]byte(*ptr))) // 32 
fmt.Printf("%T %q\n", ptr, *ptr) // *string "" 

образец кода B (с комментариями выход):

var ptr2 *string    // ptr2 has value nil, static type *string 
fmt.Printf("%T %#[1]v\n", ptr2) // *string (*string)(nil) 
//fmt.Println(len(*ptr2)) // panic: runtime error: invalid memory address or nil pointer dereference 
//fmt.Println(cap([]byte(*ptr2))) 

образец кода с (с комментариями выход):

var str string    // str has value "", static type string 
fmt.Println(len(str))   // 0 
fmt.Println(cap([]byte(str))) // 32 
fmt.Printf("%T %[1]q\n", str) // string "" 

Распределение:

Встроенная функция нового принимает тип Т, выделяет память для переменной этого типа во время выполнения, и возвращает значение типа * T указывая на него. Переменная инициализируется, как описано в разделе на initial values.

new(T) 

Например

type S struct { a int; b float64 } 
new(S) 

выделяет память для переменной типа S, инициализирует его (а = 0, Ь = 0,0), и возвращает значение типа * S, содержащий адрес .

исх: https://golang.org/ref/spec

Allocation с новым:

Go имеет два примитива распределения, встроенный в функции новых и сделать. Они делают разные вещи и применяют к разные типы, которые могут ввести в заблуждение, но правила просты. Давайте поговорим о новых первых. Это встроенная функция, которая выделяет память, но в отличие от своих однофамильцев на некоторых других языках она не инициализирует память, она только нулирует ее. То есть новый (T) выделяет обнуленное хранилище для нового элемента типа T и возвращает его адрес, значение типа * T. В терминологии Go, он возвращает указатель на вновь выделяемых нулевого значение типа T.

Поскольку память возвращаемой новым обнуляются, полезно организовать при проектировании ваших структур данных, что нулевое значения каждого типа можно использовать без дальнейшей инициализации. Это означает, что пользователь структуры данных может создать новую и получить право на работу. Например, для документации для байтов. Буффер утверждает, что «значение нулевого значения для буфера - это пустой буфер, готовый к использованию». Аналогично, sync.Mutex не имеет явного конструктора или метода Init. Вместо этого нулевое значение для sync.Mutex определяется как разблокированный мьютекс .

Объект с нулевым значением полезен транзитивно. Рассмотрим это объявление типа .

type SyncedBuffer struct { 
    lock sync.Mutex 
    buffer bytes.Buffer 
} Values of type SyncedBuffer are also ready to use immediately upon allocation or just declaration. In the next snippet, both p and v 

будет корректно работать без дополнительной договоренности:

p := new(SyncedBuffer) // type *SyncedBuffer 
var v SyncedBuffer  // type SyncedBuffer 

Распределение с замыкающими: Назад к распределению. Встроенная функция make (T, args) отличается от новой (T). Он создает только фрагменты, карты и каналы и возвращает инициализированное (не ) значение типа T (not * T). Причиной отличия является , что эти три типа представляют под крышками ссылки на данные структуры, которые должны быть инициализированы перед использованием. Например, фрагмент, например, , представляет собой трехпозиционный дескриптор, содержащий указатель на данные (внутри массива ), длину и емкость, и до тех пор, пока эти элементы не будут инициализированы, срез равен нулю. Для фрагментов, карт и каналов make инициализирует внутреннюю структуру данных и подготавливает значение для использования . Например,

make([]int, 10, 100) 

выделяет массив из 100 целых чисел, а затем создает структуру среза с длиной 10 и мощностью 100 указывая на первых 10 элементов массива. (При создании фрагмента емкость может быть опущена, см. Раздел на фрагментах для получения дополнительной информации о .) Напротив, новый ([] int) возвращает указатель на недавно выделенную, обрезанную структуру среза, указатель на нулевой фрагмент значение.Эти примеры иллюстрируют разницу между новым и сделать:

var p *[]int = new([]int)  // allocates slice structure; *p == nil; rarely useful 
var v []int = make([]int, 100) // the slice v now refers to a new array of 100 ints 

// Unnecessarily complex: 
var p *[]int = new([]int) 
*p = make([]int, 100, 100) 

// Idiomatic: 
v := make([]int, 100) 

Помните, что делает распространяется только на карты, ломтики и каналы и не не возвращает указатель. Чтобы получить явный указатель, выделите его с помощью нового или явно введите адрес переменной.

исй: https://golang.org/doc/effective_go.html

+0

Итак, вывод: var s * string = & emptyString с s: = new (string)? –

+0

Коррекция: 'new()' выделяет память для значения, а не переменной. В 's: = new (string)', переменная имеет значение «s», а значение, которое она имеет, является указателем на другое значение - на этот раз строка, которая была выделена 'new()'. – kostix

+0

@Amd: Когда var выделяет память? В компиляции? - Извините немного OOT, какая разница выделяет память во время выполнения и компилируется? Кроме времени. –

4

Этот код:

var s *string 

Просто объявите "s" как указатель на строку. В этом случае «s» является указателем nil, это значение по умолчанию для golang для указателей.

Этот код:

s := new(string) 

объявить также «S» как указатель на строку, но на этот раз строка инициализируется. Это означает, что «s» - это не-nil-указатель и указывает на значение по умолчанию для строки в golang, пустую строку.

See this playground

+0

Итак, вывод: var s * string = & emptyString с s: = new (string)? –

+2

Да. Только прежняя форма поддерживается только для типов 'struct'. Но * концептуально * они одинаковы. Я также уверен, что компилятор завершит создание для них того же кода. – kostix

Смежные вопросы