I am just playing around with Go and do not yet have a good mental model of when structs are passed by value or by reference.
This may be a very dumb question but I just want to experiment a bit and see if I am still working on the same object or I have made a copy of it (passed it by value).
Is there a way to print the pointer (or internal id if pointer value is changed by gc) of an object?
package main
import ( "runtime" )
type Something struct {
number int
queue chan int
}
func gotest( s *Something, done chan bool ) {
println( "from gotest:")
println( &s )
for num := range s.queue {
println( num )
s.number = num
}
done <- true
}
func main() {
runtime.GOMAXPROCS(4)
s := new(Something)
println(&s)
s.queue = make(chan int)
done := make(chan bool)
go gotest(s, done)
s.queue <- 42
close(s.queue)
<- done
println(&s)
println(s.number)
}
gives on my windows (8g compiled version):
0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42
Why does the pointer value from within the go routine show a different value? The quantity on the original object did get changed so it was working with the same object. Is there a way to see an object id that is persistent?
Go function arguments are passed by value.
First, let’s discard the irrelevant parts of your example, so that we can easily see that you are merely passing an argument by value. For example,
Output:
In function
main,iis anintvariable at memory location (&i)0xf800000040with an initial value (i)42.In function
main,pis a pointer to anintvariable at memory location (&p)0xf8000000f0with a value (p=&i)0xf800000040which points to anintvalue (*p=i)42.In function
main,byval(p)is a function call which assigns the value (p=&i)0xf800000040of the argument at memory location (&p)0xf8000000f0to the functionbyvalparameterqat memory location (&q)0xf8000000d8. In other words, memory is allocated for thebyvalparameterqand the value of themainbyvalargumentpis assigned to it; the values ofpandqare initially the same, but the variablespandqare distinct.In function
byval, using pointerq(*int), which is a copy of pointerp(*int), integer*q(i) is set to a new int value4143. At the end before returning. the pointerqis set tonil(zero value), which has no effect onpsinceqis a copy.In function
main,pis a pointer to anintvariable at memory location (&p)0xf8000000f0with a value (p=&i)0xf800000040which points to a newintvalue (*p=i)4143.In function
main,iis anintvariable at memory location (&i)0xf800000040with a final value (i)4143.In your example, the function
mainvariablesused as an argument to the functiongotestcall is not the same as the functiongotestparameters. They have the same name, but are different variables with different scopes and memory locations. The function parametershides the function call arguments. That’s why in my example, I named the argument and parameter variablespandqrespectively to emphasize the difference.In your example, (
&s)0x4930d4is the address of the memory location for the variablesin functionmainthat is used as an argument to the function callgotest(s, done), and0x4974d8is the address of the memory location for the functiongotestparameters. If you set parameters = nilat the end of functiongotest, it has no effect on variablesinmain;sinmainandsingotestare distinct memory locations. In terms of types,&sis**Something,sis*Something, and*sisSomething.&sis a pointer to (address of memory location)s, which is a pointer to (address of memory location) an anonymous variable of typeSomething. In terms of values,main.&s != gotest.&s,main.s == gotest.s,main.*s == gotest.*s, andmain.s.number == gotest.s.number.You should take mkb’s sage advice and stop using
println(&s). Use thefmtpackage, for example,Pointers have the same value when they point to the same memory location; pointers have different values when they point to different memory locations.