我只是在玩Go,并且还没有一个很好的心理模型,可以通过值或参考传递结构。
这可能是一个非常愚蠢的问题,但我只是想稍微试验一下,看看我是否还在处理同一个对象,或者我已经复制了它(通过值传递它)。
有没有办法打印对象的指针(如果指针值被gc改变,则为内部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)
}
在我的窗口上给出(8g编译版本):
0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42
为什么go例程中的指针值显示不同的值?原始对象上的数量确实发生了变化,因此它使用了同一个对象。有没有办法看到持久的对象ID?
答案 0 :(得分:75)
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
的{{1}}变量的指针,其值为0xf8000000f0
} = p
)&i
指向0xf800000040
值(int
= *p
)i
。
在函数42
中,main
是一个函数调用,它在内存位置分配参数的值(byval(p)
= p
)&i
({ {1}})0xf800000040
到内存位置(&p
)0xf8000000f0
的函数byval
参数q
。换句话说,为&q
参数0xf8000000d8
分配了内存,并为其分配了byval
q
参数main
的值; byval
和p
的值最初相同,但变量p
和q
是不同的。
在函数p
中,使用指针q
(byval
),它是指针q
(*int
)的副本,整数{{1} }(p
)设置为新的int值*int
。在返回之前结束。指针*q
设置为i
(零值),这对4143
没有影响,因为q
是副本。
在函数nil
中,p
是指向内存位置q
)main
的{{1}}变量的指针,其值为p
} = int
)&p
指向新的0xf8000000f0
值(p
= &i
)0xf800000040
。
在功能int
中,*p
是内存位置的i
变量(4143
)main
,其最终值为i
) int
。
在您的示例中,用作函数&i
调用的参数的函数0xf800000040
变量i
与函数4143
参数{{1}不同}。它们具有相同的名称,但是具有不同范围和内存位置的不同变量。函数参数main
隐藏函数调用参数s
。这就是为什么在我的例子中,我分别命名参数和参数变量gotest
和gotest
来强调差异。
在您的示例中,(s
)s
是函数s
中变量p
的内存位置的地址,用作函数的参数致电q
,&s
是函数0x4930d4
参数s
的内存位置地址。如果您在函数main
的末尾设置参数gotest(s, done)
,则它对0x4974d8
中的变量gotest
没有影响; s
中的s = nil
和gotest
中的s
是不同的记忆位置。就类型而言,main
为s
,main
为s
,gotest
为&s
。 **Something
是指向(内存位置的地址)s
的指针,它是指向({1}}类型的匿名变量的指针(内存位置的地址)。就价值而言,*Something
,*s
,Something
和&s
。
你应该接受mkb的sage建议并停止使用s
。使用Something
包,例如
main.&s != gotest.&s
当指针指向相同的内存位置时,指针具有相同的值;当指针指向不同的内存位置时,它们具有不同的值。
答案 1 :(得分:5)
在Go中,参数按值传递。
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)
}
输出:
s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
答案 2 :(得分:1)
type sometype struct { }
a := sometype {}
b := int(2)
println("Ptr to a", &a)
println("Ptr to b", &b)
答案 3 :(得分:1)
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)
}
输出:
$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
答案 4 :(得分:0)