Когда вы объявляете переменную, где T
некоторый тип:
var name T
Go дает вам кусок неинициализированным «обнуляется» память.
С примитивами это означает, что var name int
будет 0, а var name string
будет "". В C it might be zeroed, or might be something unexpected. Go гарантирует, что неинициализированная переменная является нулевым эквивалентом типа.
Внутренние фрагменты, карты и каналы рассматриваются как указатели. Нулевое значение указателей равно nil, что означает, что он указывает на nil-память. Не инициализируя его, вы можете столкнуться с паникой, если попытаетесь оперировать ею.
Функция make
специально предназначена для фрагмента, карты или канала. Аргументы сделать функцию, являются:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
A ломтиков length
, сколько предметов начинается с. Емкость - это выделенная память, прежде чем потребуется изменить размер (внутренне, новый размер * 2, затем скопируйте). Для получения дополнительной информации см. Effective Go: Allocation with make.
Структуры: new(T)
равнозначно &T{}
, а не T{}
. *new(T)
эквивалентен *&T{}
.
Кусочки: make([]T,0)
равнозначно []T{}
.
Карты: make(map[T]T)
эквивалентно map[T]T{}
.
Насколько который предпочтителен метод, я задаю себе вопрос:
Вы знаете, я стоимость (ы) сейчас в функции?
Если ответ «да», то я иду с одним из вышеуказанных T{...}
. Если ответ «нет», я использую make или new.
К примеру, я бы избежать чего-то вроде этого:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
Вместо этого я бы сделать что-то вроде этого:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
Почему? Потому что, используя new(Name)
, я даю понять, что I intend для заполнения значений позже. Если бы я использовал , было бы непонятно, что я собирался добавить/изменить значение позже в той же функции, не читая остальную часть кода.
Исключение составляют структуры, если вы не хотите указатель. Я буду использовать T{}
, но я не буду ничего вкладывать в него, если планирую добавить/изменить значения. Конечно, *new(T)
также работает, но это похоже на использование *&T{}
. В этом случае T{}
является более чистым, хотя я стараюсь использовать указатели со структурами, чтобы избежать копирования при передаче.
Другое дело иметь в виду, что размер []*struct
меньше и дешевле, чем []struct
, предполагая, что структура намного больше, чем указатель, который обычно составляет 4-8 байт (8 байтов на 64 бит?).
+1 Не отвечает на вопрос, но я точно согласен - рад узнать, что сам Пайк так сказал. Это одна слабость, которую я нахожу в GoLang: слишком много способов объявить и не понять преимущества, недостатки и уместность каждого из них - иногда дает мне некоторое «не совсем законченное» чувство. – Vector