I'm going through the golang tutorials at http://tour.golang.org/, and was experimenting a bit with some things in example 29
For your reference, the original example is copied here:
package main import "fmt" type Vertex struct { X, Y int } var ( p = Vertex{1, 2} // has type Vertex q = &Vertex{1, 2} // has type *Vertex r = Vertex{X: 1} // Y:0 is implicit s = Vertex{} // X:0 and Y:0 ) func main() { fmt.Println(p, q, r, s) }
It's pretty basic, showing how to create instances of this fancy new struct, Vertex
. Example 28, though, shows manipulating a vertex via a pointer to it, so I modified the example a bit and was surprised by the output. Here is the modification:
func main() { t := *q q.X = 4 u := *q fmt.Println(p, q, r, s, t, u, t == u) }
And the output:
{1 2} &{4 2} {1 0} {0 0} {1 2} {4 2} false
The thing that surprised me is that t
is not {4, 2}, which seems to mean that changing q.X
changed the instance of the struct that q
pointed to. Coming from a C/C++ background, this seems like extremely strange behavior to me.
So, what's actually going on here? Why does using q.X = 4
to change the Vertex not propagate to t
?
Pointers can be dereferenced by adding an asterisk * before a pointer.
Pointers in Go programming language or Golang is a variable that is used to store the memory address of another variable. Pointers in Golang is also termed as the special variables. The variables are used to store some data at a particular memory address in the system.
Go performs automatic dereferencing for struct data type in its specification. Hence, you do not need to de-reference it explicitly. Quote: As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).
Dereferencing is used to access or manipulate data contained in memory location pointed to by a pointer. *(asterisk) is used with pointer variable when dereferencing the pointer variable, it refers to variable being pointed, so this is called dereferencing of pointers.
t := *q
makes a copy of the struct pointed to by q
.
If you want to observe changes to q
through t
, then stick with a pointer:
var ( p = Vertex{1, 2} // has type Vertex q = &Vertex{1, 2} // has type *Vertex r = Vertex{X: 1} // Y:0 is implicit s = Vertex{} // X:0 and Y:0 ) func main() { t := q q.X = 4 u := *q fmt.Println(p, q, r, s, t, u, *t == u) }
This produces the output you were probably looking for.
{1 2} &{4 2} {1 0} {0 0} &{4 2} {4 2} true
I'm not sure what seems extremely strange to you. C and C++ behave the same way. Consider the following:
#include <iostream> struct Vertex { int x; int y; }; std::ostream& operator<<(std::ostream& out, const Vertex& v) { out << "{ " << v.x << ", " << v.y << " }"; return out; } int main() { Vertex v = Vertex{1, 2}; Vertex* q = &v; Vertex t = *q; q->x = 4; std::cout << "*q: " << *q << "\n"; std::cout << " t: " << t << "\n"; }
The output of this C++ code shows the same behavior:
*q: { 4, 2 } t: { 1, 2 }
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