英文:
How do I print the pointer value of a Go object? What does the pointer value mean?
问题
我只返回翻译好的部分,不要有别的内容:
我只是在玩Go,并且还没有一个很好的心智模型来判断结构体是按值传递还是按引用传递。
这可能是一个非常愚蠢的问题,但我只是想做一些实验,看看我是否仍然在处理同一个对象,还是已经复制了它(按值传递)。
有没有办法打印对象的指针(或者如果指针值被垃圾回收更改了,打印内部ID)?
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)
}
在我的Windows上(使用8g编译版本)输出:
0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42
为什么go例程内部的指针值显示不同?原始对象上的数量确实发生了变化,所以它正在处理同一个对象。有没有办法看到一个持久的对象ID?
英文:
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?
答案1
得分: 142
Go函数的参数是按值传递的。
首先,让我们丢弃你的示例中无关的部分,这样我们就可以清楚地看到你只是通过值传递一个参数。例如,
package main
import "fmt"
func byval(q *int) {
fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
*q = 4143
fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
q = nil
}
func main() {
i := int(42)
fmt.Printf("1. main -- i %T: &i=%p i=%v\n", i, &i, i)
p := &i
fmt.Printf("2. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
byval(p)
fmt.Printf("5. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
fmt.Printf("6. main -- i %T: &i=%p i=%v\n", i, &i, i)
}
输出:
1. main -- i int: &i=0xf840000040 i=42
2. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=4143
5. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=4143
6. main -- i int: &i=0xf840000040 i=4143
在函数main
中,i
是一个int
变量,位于内存位置(&i
)0xf800000040
,具有初始值(i
)42
。
在函数main
中,p
是一个指向int
变量的指针,位于内存位置(&p
)0xf8000000f0
,具有值(p
=&i
)0xf800000040
,它指向一个int
值(*p
=i
)42
。
在函数main
中,byval(p)
是一个函数调用,它将内存位置(&p
)0xf8000000f0
处的参数值(p
=&i
)0xf800000040
分配给函数byval
的参数q
的内存位置(&q
)0xf8000000d8
。换句话说,为byval
参数q
分配了内存,并将main
的byval
参数p
的值分配给它;p
和q
的值最初相同,但变量p
和q
是不同的。
在函数byval
中,使用指针q
(*int
),它是指针p
(*int
)的副本,将整数*q
(i
)设置为新的整数值4143
。在返回之前,将指针q
设置为nil
(零值),这对p
没有影响,因为q
是一个副本。
在函数main
中,p
是一个指向int
变量的指针,位于内存位置(&p
)0xf8000000f0
,具有值(p
=&i
)0xf800000040
,它指向一个新的int
值(*p
=i
)4143
。
在函数main
中,i
是一个int
变量,位于内存位置(&i
)0xf800000040
,具有最终值(i
)4143
。
在你的示例中,作为函数gotest
调用的参数使用的函数main
变量s
与函数gotest
参数s
不同。它们具有相同的名称,但是具有不同的变量作用域和内存位置。函数参数s
隐藏了函数调用参数s
。这就是为什么在我的示例中,我将参数和参数变量分别命名为p
和q
以强调它们的区别。
在你的示例中,(&s
)0x4930d4
是函数main
中变量s
的内存位置的地址,它被用作函数调用gotest(s, done)
的参数,而0x4974d8
是函数gotest
参数s
的内存位置的地址。如果你在函数gotest
的末尾将参数s
设置为nil
,它对main
中的变量s
没有影响;main
中的s
和gotest
中的s
是不同的内存位置。就类型而言,&s
是**Something
,s
是*Something
,*s
是Something
。&s
是指向(内存位置的地址)s
的指针,它是指向(内存位置的地址)类型为Something
的匿名变量的指针。就值而言,main.&s != gotest.&s
,main.s == gotest.s
,main.*s == gotest.*s
,main.s.number == gotest.s.number
。
你应该采纳mkb的明智建议,停止使用println(&s)
。使用fmt
包,例如,
fmt.Printf("%v %p %v\n", &s, s, *s)
当指针指向相同的内存位置时,指针具有相同的值;当指针指向不同的内存位置时,指针具有不同的值。
英文:
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,
package main
import "fmt"
func byval(q *int) {
fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
*q = 4143
fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
q = nil
}
func main() {
i := int(42)
fmt.Printf("1. main -- i %T: &i=%p i=%v\n", i, &i, i)
p := &i
fmt.Printf("2. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
byval(p)
fmt.Printf("5. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
fmt.Printf("6. main -- i %T: &i=%p i=%v\n", i, &i, i)
}
Output:
1. main -- i int: &i=0xf840000040 i=42
2. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=4143
5. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=4143
6. main -- i int: &i=0xf840000040 i=4143
In function main
, i
is an int
variable at memory location (&i
) 0xf800000040
with an initial value (i
) 42
.
In function main
, p
is a pointer to an int
variable at memory location (&p
) 0xf8000000f0
with a value (p
=&i
) 0xf800000040
which points to an int
value (*p
=i
) 42
.
In function main
, byval(p)
is a function call which assigns the value (p
=&i
) 0xf800000040
of the argument at memory location (&p
) 0xf8000000f0
to the function byval
parameter q
at memory location (&q
) 0xf8000000d8
. In other words, memory is allocated for the byval
parameter q
and the value of the main
byval
argument p
is assigned to it; the values of p
and q
are initially the same, but the variables p
and q
are distinct.
In function byval
, using pointer q
(*int
), which is a copy of pointer p
(*int
), integer *q
(i
) is set to a new int value 4143
. At the end before returning. the pointer q
is set to nil
(zero value), which has no effect on p
since q
is a copy.
In function main
, p
is a pointer to an int
variable at memory location (&p
) 0xf8000000f0
with a value (p
=&i
) 0xf800000040
which points to a new int
value (*p
=i
) 4143
.
In function main
, i
is an int
variable at memory location (&i
) 0xf800000040
with a final value (i
) 4143
.
In your example, the function main
variable s
used as an argument to the function gotest
call is not the same as the function gotest
parameter s
. They have the same name, but are different variables with different scopes and memory locations. The function parameter s
hides the function call argument s
. That's why in my example, I named the argument and parameter variables p
and q
respectively to emphasize the difference.
In your example, (&s
) 0x4930d4
is the address of the memory location for the variable s
in function main
that is used as an argument to the function call gotest(s, done)
, and 0x4974d8
is the address of the memory location for the function gotest
parameter s
. If you set parameter s = nil
at the end of function gotest
, it has no effect on variable s
in main
; s
in main
and s
in gotest
are distinct memory locations. In terms of types, &s
is **Something
, s
is *Something
, and *s
is Something
. &s
is a pointer to (address of memory location) s
, which is a pointer to (address of memory location) an anonymous variable of type Something
. In terms of values, main.&s != gotest.&s
, main.s == gotest.s
, main.*s == gotest.*s
, and main.s.number == gotest.s.number
.
You should take mkb's sage advice and stop using println(&s)
. Use the fmt
package, for example,
fmt.Printf("%v %p %v\n", &s, s, *s)
Pointers have the same value when they point to the same memory location; pointers have different values when they point to different memory locations.
答案2
得分: 12
在Go语言中,参数是按值传递的。
package main
import "fmt"
type SomeStruct struct {
e int
}
// 结构体按值传递
func v(v SomeStruct) {
fmt.Printf("v: %p %v\n", &v, v)
v.e = 2
fmt.Printf("v: %p %v\n", &v, v)
}
// 指向结构体的指针按值传递
func p(p *SomeStruct) {
fmt.Printf("p: %p %v\n", p, *p)
p.e = 2
fmt.Printf("p: %p %v\n", p, *p)
}
func main() {
var s SomeStruct
s.e = 1
fmt.Printf("s: %p %v\n", &s, s)
v(s)
fmt.Printf("s: %p %v\n", &s, s)
p(&s)
fmt.Printf("s: %p %v\n", &s, s)
}
输出结果:
s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
英文:
In Go, arguments are passed by value.
package main
import "fmt"
type SomeStruct struct {
e int
}
// struct passed by value
func v(v SomeStruct) {
fmt.Printf("v: %p %v\n", &v, v)
v.e = 2
fmt.Printf("v: %p %v\n", &v, v)
}
// pointer to struct passed by value
func p(p *SomeStruct) {
fmt.Printf("p: %p %v\n", p, *p)
p.e = 2
fmt.Printf("p: %p %v\n", p, *p)
}
func main() {
var s SomeStruct
s.e = 1
fmt.Printf("s: %p %v\n", &s, s)
v(s)
fmt.Printf("s: %p %v\n", &s, s)
p(&s)
fmt.Printf("s: %p %v\n", &s, s)
}
Output:
s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
答案3
得分: 2
type sometype struct { }
a := sometype {}
b := int(2)
println("Ptr to a", &a)
println("Ptr to b", &b)
英文:
type sometype struct { }
a := sometype {}
b := int(2)
println("Ptr to a", &a)
println("Ptr to b", &b)
答案4
得分: 2
如何打印Go对象的指针值?
package main
import (
"fmt"
)
func main() {
a := 42
fmt.Println(&a)
}
结果为:
0x1040a124
指针值的含义是什么?
根据Wikipedia的解释:
指针引用了内存中的一个位置
英文:
> How do I print the pointer value of a Go object?
package main
import (
"fmt"
)
func main() {
a := 42
fmt.Println(&a)
}
results in:
0x1040a124
> What does the pointer value mean?
According to Wikipedia:
> A pointer references a location in memory
答案5
得分: 1
包 main
import "fmt"
func zeroval(ival int) {
ival = 0
}
func zeroptr(iptr *int) {
*iptr = 0
}
func main() {
i := 1
fmt.Println("初始值:", i)
zeroval(i)
fmt.Println("zeroval:", i)
// &i 语法给出了 i 的内存地址,即 i 的指针。
zeroptr(&i)
fmt.Println("zeroptr:", i)
// 指针也可以打印出来。
fmt.Println("指针:", &i)
}
输出:
$ go run pointers.go
初始值: 1
zeroval: 1
zeroptr: 0
指针: 0x42131100
英文:
package main
import "fmt"
func zeroval(ival int) {
ival = 0
}
func zeroptr(iptr *int) {
*iptr = 0
}
func main() {
i := 1
fmt.Println("initial:", i)
zeroval(i)
fmt.Println("zeroval:", i)
//The &i syntax gives the memory address of i, i.e. a pointer to i.
zeroptr(&i)
fmt.Println("zeroptr:", i)
//Pointers can be printed too.
fmt.Println("pointer:", &i)
}
OUTPUT:
$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论