Consider the following example. I don't fully understand what happens "in the background" and seek an explanation. This version seems to make a copy of the struct Foo
when I call AddToEntry
from the main function. Right? How can I "proof" this in the code?
When go makes a copy of the struct, I am just manipulating the copy of the struct and when I get back to the main
function I see the original as before?
When I expect a pointer (see comment in the code), everything is fine, my struct is not copied. How can avoid this kind of "error"? How can I make sure I am not copying the struct? Is there a possible compile time/run time check for that, or do I have be careful?
package main
import (
"fmt"
)
type Foo struct {
Entry []string
}
func MakeFoo() Foo {
a:=Foo{}
a.Entry = append(a.Entry,"first")
return a
}
// if I change (f Foo) to (f *Foo), I get
// the "desired" result
func (f Foo) AddToEntry() {
f.Entry = append(f.Entry,"second")
}
func main() {
f:=MakeFoo()
fmt.Println(f) // {[first]}
f.AddToEntry()
fmt.Println(f) // {[first]}
}
Your method signature is func (f Foo) AddToEntry()
. The way methods work, f.AddToEntry()
is is the same as:
g := Foo.AddToEntry
g(f)
The receiver is just another parameter. Why is this important? What happens when you pass a struct and modify it in a function? In C, Go, and other pass by value languages, the struct given in the parameter is only a copy. Therefore, you can not modify the original. Only return the new struct.
When you define func (f *Foo) AddToEntry()
, you are defining the receiver, the first parameter, as a pointer. Obviously, given a pointer, you can modify the original struct. What is hidden is that you are implicitly referencing when you access a struct in Go. To put it another way, (*ptrFoo).Entry
is the same as ptrFoo.Entry
in Go.
So the issue here is that for those unaccustomed to go, the syntax is hiding some of what is going on. In C, you would never be able to edit a struct unless you passed a pointer to it. The same happens in Go. You need to use a pointer receiver in order to modify what you are receiving.
Have you read this Go documentation?
How can I make sure I am not copying the struct? Is there a possible compile time/run time check for that, or do I have be careful?
The short answer here is that no , you can't do a compile-time or run-time(1) check for this - you just have to be careful. Once you get a bit familiar with go, this becomes natural.
(1) Technically your function could query whether the type is a pointer or not with the type switch, but if you remember to do that, you'll also remember to make the parameter a pointer.