英文:
Why does the memory address of a struct reference change?
问题
我有一个结构体和一个在结构体引用上工作的方法。每次调用该方法时,指针地址都会发生变化。为什么会这样呢?
代码:
package main
import "k8s.io/contrib/compare/Godeps/_workspace/src/github.com/emicklei/go-restful/log"
type Whatever struct {
Name string
}
func (whatever *Whatever) GetNameByReference() string {
log.Printf("Whatever.GetNameByReference() memory address: %v", &whatever)
return whatever.Name
}
func evaluateMemoryAddressWhenNotWritingAnything() {
whatever := Whatever{}
whatever.GetNameByReference()
whatever.GetNameByReference()
whatever.GetNameByReference()
}
func main() {
evaluateMemoryAddressWhenNotWritingAnything()
}
输出:
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034020
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034030
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034038
英文:
I have a struct and a method that's working on the structs reference. The pointer address is changing every time I call the method. Why is it like that?
Code
package main
import "k8s.io/contrib/compare/Godeps/_workspace/src/github.com/emicklei/go-restful/log"
type Whatever struct{
Name string
}
func (whatever *Whatever) GetNameByReference() (string) {
log.Printf("Whatever.GetNameByReference() memory address: %v", &whatever)
return whatever.Name
}
func evaluateMemoryAddressWhenNotWritingAnything() {
whatever := Whatever{}
whatever.GetNameByReference()
whatever.GetNameByReference()
whatever.GetNameByReference()
}
func main() {
evaluateMemoryAddressWhenNotWritingAnything()
}
Output:
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034020
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034030
log.go:30: Whatever.GetNameByReference() memory address: 0xc420034038
答案1
得分: 12
永远不要考虑和谈论引用。Go语言没有"引用"的概念,一切都是值。有些东西是指针值。你的问题源于将*X
视为"对X的引用",但实际上它不是:它是一个保存了X
的内存地址(或者是nil)的值。
所以在func (whatever *Whatever)
中,变量whatever
是指向Whatever
的指针。whatever
的值是指针所指向的Whatever
的内存地址。你想要打印这个内存地址,也就是whatever
的值。
你使用了Printf("%v", &whatever)
。记住:whatever
是一个变量(保存了一个内存地址)。所以&whatever
是变量本身的地址:&whatever
的类型是**Whatever
。在地址&whatever
上找到的内容并不是你感兴趣的值;它只是用于存储原始Whatever
地址的临时变量。当然,这个临时变量并没有固定在内存中,可以自由改变。
你应该使用Printf("%p", whatever)
。占位符%p
用于指针值,而whatever
是一个指针,你对它的值感兴趣,所以打印这个值。
英文:
Never think and never talk about references. Go has no notion of "reference", everything is a value. Some things are pointer values. Your problem stems from thinking about *X
as "a reference to an X" which it isn't: It is a value holding the memory address of an X
(or nil).
So in func (whatever *Whatever)
the variable whatever
is a pointer to a Whatever
. The value of whatever
is the memory address of the Whatever
the pointer points to. You would like to print this memory address, i.e. the value of whatever
.
You do Printf("%v", &whatever)
. Remember: whatever
is a variable (holding a memory address). So &whatever
is the address of the variable itself: &whatever
is of type **Whatever
. What you find at the address &whatever
is not the value you are interested in; it is just the temporary variable used to store the address of the original Whatever
. Of course this temporary variable is not pinned in memory an may change freely.
You should do Printf("%p", whatever)
. The verb %p
is for pointer values and whatever
is a pointer and you are interested in its value, so print this value.
答案2
得分: 3
你没有显示结构体的地址,而是显示了地址的地址(指针的地址)。指针作为参数传递,因此每次都是新的。删除log.Printf("Whatever.GetNameByReference() memory address: %v", &whatever)
中的&
,以获得你想要的结果(并使用%p
代替%v
)。
英文:
You are not displaying the address of the struct, you are displaying the address of the address (address of the pointer). The pointer is passed as a parameter and thus new each time. Remove the & in log.Printf("Whatever.GetNameByReference() memory address: %v", &whatever)
to get what you want (and use %p instead of %v).
答案3
得分: 0
调用方法
func (whatever *Whatever) GetNameByReference() (string) {
与调用函数并将接收器作为第一个参数提供的方式几乎相同
func GetNameByReference(whatever *Whatever) (string) {
Go的调用约定是始终通过值传递参数。因此,每次调用whatever.GetNameByReference()
时,它都会接收到whatever
的新副本,该副本本身保存着相同的*Whatever
地址。如上所述,使用以下方式记录日志
log.Printf("Whatever.GetNameByReference() memory address: %v", whatever) //instead of &whatever
将记录相同的whatever
值,即地址。
英文:
Calling method
func (whatever *Whatever) GetNameByReference() (string) {
is much the same as calling function providing receiver as first argument
func GetNameByReference(whatever *Whatever) (string) {
Go calling convention is to always pass arguments copy_by_value. So each time you call whatever.GetNameByReference()
it receives fresh copy of whatever
which itself holds same *Whatever
address. As already written doing
log.Printf("Whatever.GetNameByReference() memory address: %v", whatever) //instead of &whatever
will log the same whatever
value which is address.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论