如何打印Go对象的指针值?指针值代表什么意思?

huangapple go评论97阅读模式
英文:

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 ( &quot;runtime&quot; )

type Something struct {
	number int
	queue chan int
}

func gotest( s *Something, done chan bool ) {
	println( &quot;from gotest:&quot;)
	println( &amp;s )
	for num := range s.queue {
		println( num )
		s.number = num
	}
	done &lt;- true
}

func main() {
	runtime.GOMAXPROCS(4)
	s := new(Something)
	println(&amp;s)
	s.queue = make(chan int)
	done := make(chan bool)
	go gotest(s, done)
	s.queue &lt;- 42
	close(s.queue)
	&lt;- done
	println(&amp;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变量,位于内存位置(&i0xf800000040,具有初始值(i42

在函数main中,p是一个指向int变量的指针,位于内存位置(&p0xf8000000f0,具有值(p=&i0xf800000040,它指向一个int值(*p=i42

在函数main中,byval(p)是一个函数调用,它将内存位置(&p0xf8000000f0处的参数值(p=&i0xf800000040分配给函数byval的参数q的内存位置(&q0xf8000000d8。换句话说,为byval参数q分配了内存,并将mainbyval参数p的值分配给它;pq的值最初相同,但变量pq是不同的。

在函数byval中,使用指针q*int),它是指针p*int)的副本,将整数*qi)设置为新的整数值4143。在返回之前,将指针q设置为nil(零值),这对p没有影响,因为q是一个副本。

在函数main中,p是一个指向int变量的指针,位于内存位置(&p0xf8000000f0,具有值(p=&i0xf800000040,它指向一个新的int值(*p=i4143

在函数main中,i是一个int变量,位于内存位置(&i0xf800000040,具有最终值(i4143

在你的示例中,作为函数gotest调用的参数使用的函数main变量s与函数gotest参数s不同。它们具有相同的名称,但是具有不同的变量作用域和内存位置。函数参数s隐藏了函数调用参数s。这就是为什么在我的示例中,我将参数和参数变量分别命名为pq以强调它们的区别。

在你的示例中,(&s0x4930d4是函数main中变量s的内存位置的地址,它被用作函数调用gotest(s, done)的参数,而0x4974d8是函数gotest参数s的内存位置的地址。如果你在函数gotest的末尾将参数s设置为nil,它对main中的变量s没有影响;main中的sgotest中的s是不同的内存位置。就类型而言,&s**Somethings*Something*sSomething&s是指向(内存位置的地址)s的指针,它是指向(内存位置的地址)类型为Something的匿名变量的指针。就值而言,main.&s != gotest.&smain.s == gotest.smain.*s == gotest.*smain.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 &quot;fmt&quot;

func byval(q *int) {
	fmt.Printf(&quot;3. byval -- q %T: &amp;q=%p q=&amp;i=%p  *q=i=%v\n&quot;, q, &amp;q, q, *q)
	*q = 4143
	fmt.Printf(&quot;4. byval -- q %T: &amp;q=%p q=&amp;i=%p  *q=i=%v\n&quot;, q, &amp;q, q, *q)
	q = nil
}

func main() {
	i := int(42)
	fmt.Printf(&quot;1. main  -- i  %T: &amp;i=%p i=%v\n&quot;, i, &amp;i, i)
	p := &amp;i
	fmt.Printf(&quot;2. main  -- p %T: &amp;p=%p p=&amp;i=%p  *p=i=%v\n&quot;, p, &amp;p, p, *p)
	byval(p)
	fmt.Printf(&quot;5. main  -- p %T: &amp;p=%p p=&amp;i=%p  *p=i=%v\n&quot;, p, &amp;p, p, *p)
	fmt.Printf(&quot;6. main  -- i  %T: &amp;i=%p i=%v\n&quot;, i, &amp;i, i)
}

Output:

1. main  -- i  int: &amp;i=0xf840000040 i=42
2. main  -- p *int: &amp;p=0xf8400000f0 p=&amp;i=0xf840000040  *p=i=42
3. byval -- q *int: &amp;q=0xf8400000d8 q=&amp;i=0xf840000040  *q=i=42
4. byval -- q *int: &amp;q=0xf8400000d8 q=&amp;i=0xf840000040  *q=i=4143
5. main  -- p *int: &amp;p=0xf8400000f0 p=&amp;i=0xf840000040  *p=i=4143
6. main  -- i  int: &amp;i=0xf840000040 i=4143

In function main, i is an int variable at memory location (&amp;i) 0xf800000040 with an initial value (i) 42.

In function main, p is a pointer to an int variable at memory location (&amp;p) 0xf8000000f0 with a value (p=&amp;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=&amp;i) 0xf800000040 of the argument at memory location (&amp;p) 0xf8000000f0 to the function byval parameter q at memory location (&amp;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 (&amp;p) 0xf8000000f0 with a value (p=&amp;i) 0xf800000040 which points to a new int value (*p=i) 4143.

In function main, i is an int variable at memory location (&amp;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, (&amp;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, &amp;s is **Something, s is *Something, and *s is Something. &amp;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.&amp;s != gotest.&amp;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(&amp;s). Use the fmt package, for example,

fmt.Printf(&quot;%v %p %v\n&quot;, &amp;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 &quot;fmt&quot;

type SomeStruct struct {
	e int
}

// struct passed by value
func v(v SomeStruct) {
	fmt.Printf(&quot;v: %p %v\n&quot;, &amp;v, v)
	v.e = 2
	fmt.Printf(&quot;v: %p %v\n&quot;, &amp;v, v)
}

// pointer to struct passed by value
func p(p *SomeStruct) {
	fmt.Printf(&quot;p: %p %v\n&quot;, p, *p)
	p.e = 2
	fmt.Printf(&quot;p: %p %v\n&quot;, p, *p)
}

func main() {
	var s SomeStruct
	s.e = 1
	fmt.Printf(&quot;s: %p %v\n&quot;, &amp;s, s)
	v(s)
	fmt.Printf(&quot;s: %p %v\n&quot;, &amp;s, s)
	p(&amp;s)
	fmt.Printf(&quot;s: %p %v\n&quot;, &amp;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(&quot;Ptr to a&quot;, &amp;a)
println(&quot;Ptr to b&quot;, &amp;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 (
	&quot;fmt&quot;
)

func main() {
	a := 42
	fmt.Println(&amp;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 &quot;fmt&quot;

func zeroval(ival int) {
     ival = 0
}

func zeroptr(iptr *int) {
     *iptr = 0
}

func main() {
    i := 1
    fmt.Println(&quot;initial:&quot;, i)
    zeroval(i)
    fmt.Println(&quot;zeroval:&quot;, i)
    //The &amp;i syntax gives the memory address of i, i.e. a pointer to i.
    zeroptr(&amp;i)
    fmt.Println(&quot;zeroptr:&quot;, i)
    //Pointers can be printed too.
    fmt.Println(&quot;pointer:&quot;, &amp;i)
}

OUTPUT:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100

huangapple
  • 本文由 发表于 2011年2月9日 05:22:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/4938612.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定