For example
var myStructRef *Vertex var myStruct Vertex myStructRef = &Vertex{2, 3} myStruct = Vertex{2, 3} fmt.Println(myStructRef) fmt.Println(myStruct) changeByReferenceStruct(myStructRef) changeByValueStruct(myStruct) fmt.Println(myStructRef) fmt.Println(myStruct)
And
func changeByValueStruct(myStruct Vertex) { myStruct.X = 5 fmt.Println(myStruct) } func changeByReferenceStruct(myStruct *Vertex) { myStruct.X = 7 fmt.Println(myStruct) }
Isn't both myStructRef *Vertex
and myStruct Vertex
a pointer pointing to the struct itself? Why is there a discrepancy in behavior when I modify the struct in a function?
Is golang creating a new struct in changeByValueStruct
when it resolves the parameter?
A pointer is the address of that structure (or anything else) in memory. The structure is a “blueprint” of how to store the data in memory, the pointer is the location of the data in memory. The idea of a pointer is that rather than pass the data around your program, you pass the location of the data.
A pointer pointing to a structure is called structure pointer. Structures and pointers in C together help in accessing structure members efficiently. Structure pointer declaration is similar to declaring a structure variable using the struct keyword followed by the type of structure it will point to.
A struct can be either passed/returned by value or passed/returned by reference (via a pointer) in C. The general consensus seems to be that the former can be applied to small structs without penalty in most cases.
Pointer to structure holds the add of the entire structure. It is used to create complex data structures such as linked lists, trees, graphs and so on. The members of the structure can be accessed using a special operator called as an arrow operator ( -> ).
When you pass a pointer as an argument, what happens under the hood is that a copy of that pointer is created and passed to the underlying function. It should not be confused with pass-by-reference.
Let's look at an example to better grasp it:
package main import ( "fmt" ) type Point struct { x int y int } func (p Point) String() string { return fmt.Sprintf("(%d, %d)", p.x, p.y) } func modifyValue(point Point) { point.x += 10 } func modifyPointer(point *Point) { point.x = 5 point.y = 5 } func modifyReference(point *Point) { point = &Point{5, 5} } func main() { p := Point{0, 0} fmt.Println(p) // prints (0, 0) modifyValue(p) fmt.Println(p) // prints (0, 0) modifyPointer(&p) fmt.Println(p) // prints (5, 5) p = Point{0, 0} modifyReference(&p) fmt.Println(p) // prints (0, 0) }
What happens inside the modifyValue function is that a totally different instance of a Point structure is modified, so the value passed when calling the function is unaffected.
In the second example, a pointer to the structure is passed so the fields of the structure can be modified in a way that is visible from outside.
The most interesting point is made by the last function, modifyReference. If you are familiar with the pass by reference paradigm available in other languages you would expect to be able to modify the referenced object altogether, but this doesn't happen. It's because you're modifying a copy of the pointer passed as argument.
You may wonder, if everything is passed by value, when should you pass pointers and when values. Passing values assures the caller function that the passed structure cannot suffer any changes, so when you need this behaviour, go for the value. The downside of this is that a copy of the entire object is made and, if it is too big, memory becomes a concern.
If you're passing a big structure as an argument, using a pointer is better because it saves space, but you lose the guarantee that the object won't suffer any changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With