Ответ 1
Первый способ
e1 := Event{Id: 1, Name: "event 1"}
инициализирует переменную e1
как значение типа Event
.
Второй
e2 := &Event{Id: 1, Name: "event1"}
инициализирует e2
как указатель на значение типа Event
Как вы указали в комментариях, набор методов, определенных для значения данного типа, является подмножеством набора методов, определенных на указатель на значение этого типа. Это означает, что если у вас есть метод
func (e Event) GetName() string {
return e.Name
}
тогда и e1
, и e2
могут вызывать этот метод, но если у вас был другой метод, скажите:
func (e *Event) ChangeName(s string) {
e.Name = s
}
Тогда e1
не сможет использовать метод ChangeName
, а e2
-.
Это (e1
не может использовать метод ChangeName
, в то время как e2
) это не тот случай (хотя, возможно, это было на момент написания этой справки), благодаря @DannyChen за то, что он поднял этот вопрос. и @GilbertNwaiwu для тестирования и публикации в комментариях ниже.
(Чтобы обратиться к вычеркнутому разделу выше: набор методов, определенных для типа структуры, состоит из методов, определенных для типа, и указателей на тип.
Вместо этого Go теперь автоматически разыменовывает аргумент для метода, так что если метод получает указатель, Go вызывает метод для указателя на эту структуру, а если метод получает значение, Go вызывает метод для значения, на которое указывает эта структура. На данный момент моя попытка обновить этот ответ может упустить что-то важное в семантике, поэтому, если кто-то захочет исправить это или уточнить, не стесняйтесь добавлять комментарий, указывающий на более полный ответ. Вот небольшая игровая площадка, иллюстрирующая эту проблему: https://play.golang.org/p/JcD0izXZGz.
В некоторой степени это изменение в том, как указатели и значения работают в качестве аргументов для методов, определенных для функции, влияет на некоторые области дискурса ниже, но я оставлю остальное неотредактированным, если кто-то не предложит мне обновить его, так как оно кажется более или менее правильным в контекст общей семантики языков, которые передаются по значению против указателя.)
Что касается разницы между указателями и значениями, этот пример является иллюстративным, так как указатели обычно используются в Go, чтобы позволить вам изменять значения, на которые указывает переменная (но есть еще много причин, по которым можно использовать и указатели! Хотя для типичных использовать, это обычно твердое предположение). Таким образом, если вы определили ChangeName
вместо этого как:
func (e Event) ChangeName(s string) {
e.Name = s
}
Эта функция была бы не очень полезна, если ее вызывать для получателя значения, поскольку значения (не указатели) не будут сохранять изменения, внесенные в них, если они передаются в функцию. Это связано с областью языкового проектирования, касающейся назначения и передачи переменных: В чем разница между передачей по ссылке и передачей по значению?
Вы можете увидеть это на этом примере в Go Playground: https://play.golang.org/p/j7yxvu3Fe6