Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting different values by passing Pointers to a function in Go

Say I want to pass a pointer to a function and change the value of a struct which that pointer points to by doing so. I would normally do this by dereferencing the pointer:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   *p = Test{4}
}

My question is, why this code doesn't change the value

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 2
}
func f(p *Test) {
   // ?
   p = &Test{4}
}

while this one does:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   p.Value = 4
}
like image 977
Yar Avatar asked Dec 30 '15 00:12

Yar


People also ask

How do you pass a pointer to a function in Go?

Go programming language allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.

Can you pass pointers to functions?

Pass-by-pointer means to pass a pointer argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the variable to which the pointer argument points. When you use pass-by-pointer, a copy of the pointer is passed to the function.

How do I get the value of a pointer in Go?

To find out the value (data) a pointer it points to, we need to use * operator, also called dereferencing operator which if placed before a pointer variable (like & operator to get memory address), it returns the data in that memory.

Is Golang pass-by-reference or pass by value?

While Java passes objects by reference always, Go passes by value always (i.e. it creates a copy of the value in the function); if you pass something to a function, and that function modifies that value, the caller won't see those changes.


1 Answers

Because this line:

p = &Test{4}

Just assigns a new pointer value to the p variable. Inside the f() function, p is just a local variable. By assigning any new value to p, you are just changing the value of the local variable and not the pointed value.

The p local variable in f() has nothing to do with the p local variable in main(). If you change p in f(), it will not change p in main() (and it won't change the pointed struct value either).

In your second example:

p.Value = 4

It is a shorthand for:

(*p).Value = 4

This changes the pointed value, hence you will observe the change when f() returns.

Note:

Just as a side note, if in your main() function you would pass the address of p (the local variable in main() which is a pointer) to function f(), you could modify the address stored in main's p:

func f(p **Test) {
    *p = &Test{4}
}

And from main(), call it like:

var i Test = Test{2}
var p *Test = &i
f(&p)
println(i.Value) // 2 - Note that 'i' won't change!
println(p.Value) // 4 - Only the address in 'p' to the new struct value created in f()

But obviously passing a single pointer *Test and modifying the pointed value (p.Value = 4) is more efficient, much more convenient and much cleaner.

like image 177
icza Avatar answered Sep 22 '22 06:09

icza