Can any one please explain output of this

https://play.golang.org/p/pq7ZZXOzc0W

Yes, but I’m on my mobile, therefore not many words today, but perhaps you should assign to *s in the function and the method.

What does surprise you ?

func(s *Sample)Reset(){
s = &Sample{}
}
In this method I have assigned s with some other address. But s remains unchanged.

In fact, you’re just reassigning local variables (your pointers). It has no effect on the original pointer variable.

I’m going to guess that you expect the program to behave like this.

A simpler version of the same thing is this:

func f(p *int) {
	i := 42
	p = &i
}

func main() {
	j := 1
	f(&j)
	fmt.Println(j)
}

I’m going to assume that the question is about how pointers behave. Please pardon if that assumption is incorrect.

In the above example, f takes a pointer to int, and assigns the variable p a new value inside the function.

Taking a step back, j is a variable with a value. Since everything has to be stored somewhere, it has an address (an address in memory). You obtain the address using the & operator, like &j, which is what you are doing in your example where you have &Sample{}. That Sample{} is a value that is stored somewhere. With &Sample{} you are asking for the address where that value is stored.

If you have an address, you can modify the value stored at at address. Usual assignments like k = 7 basically mean “put a 7 in the address where k is stored, whatever that might be”. Now if you have a pointer to something, like p above, what’s stored in that variable is the address where a value is stored, not the value. If you want to change the address that this points to, you store a new value in that variable, like the assignment p = &i above. But this assignment doesn’t propagate back to main (because p “doesn’t exist” in main).

This is different:

func f(p *int) {
	i := 42
	*p = i    // This is the only change
}

func main() {
	j := 1
	f(&j)
	fmt.Println(j)
}

*p means “p points somewhere, please work with that location”.

Specifically the statement *p = i means “please store the value of i in the location that p points to”. This will not change p. If you print p before the assignment, you’ll see some value. If you print p after the assignment, you’ll see the same value. If you print *p before the assignment, you’ll see 1. If you print *p after the assignment you’ll see 42. If you print j before calling f you’ll see 1. If you print j after calling f, you’ll see 42.

For contrast, consider this:

func f(p *int) {
	i := 42
	p = &i
	*p = i
}

func main() {
	j := 1
	f(&j)
	fmt.Println(j)
}

Going back to your example, func (s *Sample) Reset() is just a bit of decoration for a function that looks exactly like your second one: func Reset(s *Sample). Both are the same thing: they take the address of a Sample as their first argument and do something with it. Inside the function, that address is stored in the variable s. You can change the address that’s stored in s, or you can change the value stored at that address.

For another explanation of the same topic you can read Dave’s post, with pictures!

3 Likes

Thanks Marcelo, you explained it very well.

Think of what s = &Sample{} does. It is modifying s (not *s). s is passed to Reset() by value, so it is treated like a new local variable. So when the function returns, s is forgotten.

So of course, if you need to really reset, you need to do *s = Sample{} where the value s is pointing to is cleared. Or you can individually clear fields using (*s).data = "" and (*s).m = map[string]string{}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.