41

There is a simple struct like this:

type Event struct {
    Id         int
    Name       string
}

What is the difference between these two initialization methods?

e1 := Event{Id: 1, Name: "event 1"}
e2 := &Event{Id: 2, Name: "event 2"}

Any why would I use either of these initialization methods?

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
kind_robot
  • 2,383
  • 4
  • 31
  • 45
  • 4
    There is subtly which is not clear in the tour. There is a difference in getting a pointer vs instance itself when initializing a struct. When and why would I use one way VS the other. – kind_robot Sep 29 '16 at 15:55

2 Answers2

38

The first method

e1 := Event{Id: 1, Name: "event 1"}

is initializing the variable e1 as a value with type Event.

The second

e2 := &Event{Id: 1, Name: "event1"}

is initializing e2 as a pointer to a value of type Event As you stated in the comments, the set of methods defined on a value of a given type are a subset of the set of methods defined on a pointer to a value of that type. This means that if you have a method

func (e Event) GetName() string {
    return e.Name
}

then both e1 and e2 can call this method, but if you had another method, say:

func (e *Event) ChangeName(s string) {
    e.Name = s
}

Then e1 is not able to use the ChangeName method, while e2 is.

This (e1 is not able to use the ChangeName method, while e2 is) is not the case (although it may have been at the time of writing for this help), thanks to @DannyChen for bringing this up and @GilbertNwaiwu for testing and posting in the comments below.

(To address the striked out section above: The set of methods defined on a struct type consist of the methods defined for the type and pointers to the type.

Instead, Go now automatically dereferences the argument to a method, so that if a method receives a pointer, Go calls the method on a pointer to that struct, and if the method receives a value, Go calls the method on the value pointed to by that struct. At this point my attempt to update this answer may be missing something important in semantics so if someone would like to correct this or clarify feel free to add a comment pointing to a more comprehensive answer. Here is a bit from the go playground illustrating this issue: https://play.golang.org/p/JcD0izXZGz.

To some extent, this change in how pointers and values work as arguments to methods defined on function affects some areas of the discourse below but I will leave the rest unedited unless someone encourages me to update it as it seems to be more or less correct within the context of general semantics of languages that pass by value vs. pointer.)

As to the difference between pointers and values, this example is illustrative, as pointers are ordinarily used in Go to allow you to mutate the values a variable is pointing to (but there are many more reasons one might use pointers as well! Although for typical use, this is normally a solid assumption). Thus, if you defined ChangeName instead as:

func (e Event) ChangeName(s string) {
    e.Name = s
}

This function would not be very useful if called on the value receiver, as values (not pointers) won't keep changes that are made to them if they're passed into a function. This has to do with an area of language design around how variables are assigned and passed: What's the difference between passing by reference vs. passing by value?

You can see this on this example in the Go Playground: https://play.golang.org/p/j7yxvu3Fe6

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Clemente Cuevas
  • 486
  • 3
  • 6
  • "Then e1 is not able to use the ChangeName method, while e2 is." is this conclusion still correct? – Cheng Chen May 05 '17 at 07:34
  • @DannyChen: just tested. Not correct. Both could use the method – Gilbert Nwaiwu Jul 20 '17 at 18:16
  • @GilbertNwaiwu It seems this is not the case, consistent with what you described, I will edit the original post, thanks for finding this inconsistency. I am somewhat interested as to whether or not it has always been the case that a method defined on a pointer to a type is unable to be called by values of that type, or if this is a more recent development. – Clemente Cuevas Jul 21 '17 at 20:03
  • A cursory search shows this post: https://stackoverflow.com/questions/27775376/value-receiver-vs-pointer-receiver-in-golang Linking to this thread: http://grokbase.com/t/gg/golang-nuts/1478q5p81c/go-nuts-making-a-copy-of-a-pointer-receiver So maybe this was changed in a recent update to Go, but googling about pointer method receivers hasn't returned anything from the Go release histories. I haven't written any Go in a while, so I am out of touch with recent changes to the language, and I am not about to look through the release histories on this. Maybe someone can chime in. – Clemente Cuevas Jul 21 '17 at 20:06
  • I started on go this year and this issue was really confusing, it also stems from the fact that go accesses via pointer with the same notation as with value (ev.Name and evp.Name) unlike other languages (ev.Name vs evp->Name or *evp.Name). The Play example really clears it up. I will define methods with the * notation instead. THANKS a million! – Lord of Scripts Aug 02 '23 at 17:45
6

The type of e1 is Event the type of e2 is *Event. The initialization is actually the same (using composite literal syntax, also not sure if that jargon is Go or C# or both?) but with e2 you using the 'address of operator' & so it returns a pointer to that object rather than the instance itself.

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
  • e1.SomeMethod() vs *e2.SomeMethod is essentially the same right? Go will be doing (*e1).SomeMethod(), if I am not mistaken. – kind_robot Sep 28 '16 at 22:57
  • @sheldon_cooper not exactly, they are different types. If I had a method like `func (e *Event) Test()` and tried to do `e1.Test()` I would get a compiler error. I could do `ep := &e1` and then do `ep.Test()` or you could maybe do that inline or whatever but you would have to get the pointer in order to call the method defined with a pointer as the receiver. Basically, when calling methods, go will not massage or coerce the type for you. It must match what is in the method definition. You can convert value to pointer or pointer to value quite easily though. – evanmcdonnal Sep 28 '16 at 23:18
  • 1
    Yup, I understand the difference between reference vs value receiver types. I was referring this in the spec "A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():" URL to spec is :https://golang.org/ref/spec#Calls. Thank you for the explanation. I'll experiment with this. – kind_robot Sep 29 '16 at 16:04