我正在玩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)
}
Run Code Online (Sandbox Code Playgroud)
在我的窗口上给出(8g编译版本):
0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42
Run Code Online (Sandbox Code Playgroud)
为什么go例程中的指针值显示不同的值?原始对象上的数量确实发生了变化,因此它使用了同一个对象.有没有办法看到持久的对象ID?
pet*_*rSO 88
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)
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
在函数中main
,i
是int
内存位置(&i
)的变量,0xf800000040
带有初始值(i
)42
.
在函数中main
,p
是指向int
内存位置(&p
)的变量的指针0xf8000000f0
,其值(p
= &i
)0xf800000040
指向int
值(*p
= i
)42
.
在功能main
,byval(p)
是一个函数调用,其将值(p
= &i
)0xf800000040
在存储器位置(自变量的&p
)0xf8000000f0
给函数byval
参数q
在存储器位置(&q
)0xf8000000d8
.换句话说,存储器被分配用于byval
参数q
和的值main
byval
的参数p
被分配给它; 的值p
和q
最初是相同的,但变量p
和q
是不同的.
在功能byval
,使用指针q
(*int
),它是指针的一个拷贝p
(*int
),整数*q
(i
)被设置为一个新的int值4143
.在返回之前结束.指针q
被设置为nil
(零值),其中有不影响p
,因为q
是一个副本.
在函数中main
,p
是指向int
内存位置(&p
)的变量的指针0xf8000000f0
,其值(p
= &i
)0xf800000040
指向新int
值(*p
= i
)4143
.
在函数中main
,i
是int
内存位置(&i
)的变量,0xf800000040
带有最终值(i
)4143
.
在您的示例中,用作函数调用的参数的函数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
in main
和s
in gotest
是不同的内存位置.在类型方面,&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的sage建议并停止使用println(&s)
.fmt
例如,使用包
fmt.Printf("%v %p %v\n", &s, s, *s)
Run Code Online (Sandbox Code Playgroud)
当指针指向相同的内存位置时,指针具有相同的值; 指针指向不同的内存位置时,它们具有不同的值.
在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)
}
Run Code Online (Sandbox Code Playgroud)
输出:
s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
Run Code Online (Sandbox Code Playgroud)