英文:
Discrepancy of pointer content in golang
问题
考虑以下用于结构体和指针引用示例的代码。
package main
import (
"fmt"
"sync"
)
type myStruct struct {
mut *sync.RWMutex
}
type arrayOfMyStruct struct {
structList []myStruct
}
func main() {
k := &sync.RWMutex{}
myStructInstance := myStruct{k}
fmt.Printf("%p", &k) // 地址1 -> k的地址
fmt.Println("")
fmt.Printf("%p", &*k) // 地址2 -> k指向的地址
fmt.Println("")
var listStruct []myStruct
listStruct = append(listStruct, myStructInstance)
test := &arrayOfMyStruct{listStruct}
test.access()
}
func (elem *arrayOfMyStruct) access() {
mystructinstance := &elem.structList[0]
mystructinstance2 := elem.structList[0]
fmt.Println(&mystructinstance.mut) // 地址3
fmt.Println(&mystructinstance2.mut) // 地址4
}
为什么地址2、3和4不同?它们不应该是相同的吗?
英文:
Consider the following code for structs and pointer reference example.
package main
import (
"fmt"
"sync"
)
type myStruct struct {
mut *sync.RWMutex
}
type arrayOfMyStruct struct {
structList []myStruct
}
func main() {
k := &sync.RWMutex{}
myStructInstance := myStruct{k}
fmt.Printf("%p", &k) // address 1 -> address of k
fmt.Println("")
fmt.Printf("%p", &*k) // address 2 -> address of what k points to
fmt.Println("")
var listStruct []myStruct
listStruct = append(listStruct, myStructInstance)
test := &arrayOfMyStruct{listStruct}
test.access()
}
func (elem *arrayOfMyStruct) access() {
mystructinstance := &elem.structList[0]
mystructinstance2 := elem.structList[0]
fmt.Println(&mystructinstance.mut) // address 3
fmt.Println(&mystructinstance2.mut) // address 4
}
Why are addresses 2 3 and 4 different? Shouldn't they be the same?
答案1
得分: 1
这是要翻译的内容:
这是因为myStruct
中的mut
已经是一个指针*sync.RWMutex
,所以当你执行以下操作时:
&mystructinstance2.mut
实际上是获取了一个指向mut
的新指针,它是一个指向互斥锁的指针,类似于**sync.RWMutex
。只需在打印语句中去掉&
即可。当你使用k := &sync.RWMutex{}
创建互斥锁时,它已经是一个指针,所以在之后的任何地方都不应该再使用&
,否则它将创建一个指向该指针的新指针。你也可以使用k := new(sync.RWMutex)
来创建一个指向新互斥锁的指针。
你可以使用Printf
的%p
来打印指针地址:
fmt.Printf("%p\n", mystructinstance2.mut)
英文:
It's because mut
in myStruct
is already a pointer *sync.RWMutex
, so when you do:
&mystructinstance2.mut
You are actually getting a new pointer to mut
which is a pointer to the mutex something like **sync.RWMutex
. Just remove the &
on the print statements. When you use k := &sync.RWMutex{}
to create the mutex it's already a pointer, so you shouldn't use &
anywhere after that on that variable or it will create a new pointer to that pointer. You can also use k := new(sync.RWMutex)
to create a pointer to a new mutex.
You can use %p
on Printf to print the pointer address:
fmt.Printf("%p\n", mystructinstance2.mut)
答案2
得分: 1
地址1是指向互斥锁指针的地址。地址2是互斥锁的地址。也就是说,2指向互斥锁位的位置,1指向2中指针的位置。使用%T
而不是%p
打印将显示值的类型不同。
append
实际上是复制了你的结构体。结构体实例就像int
一样是一个值;当你将结构体追加到列表中时,实际上是复制了其中每个字段的值。
在C和Go中广泛使用结构体的值语义(也存在于C#的值类型等语言中),但在Java、JavaScript或Python等语言中不太常见。这意味着有时你需要考虑事物是指针还是非指针,但它们可以避免一些错误,防止在一个地方意外地进行更改而对其他地方产生影响(别名),并减少垃圾收集器需要跟踪的指针数量。
地址3是由append
创建的结构体副本中互斥锁指针的地址。
对mystructinstance2
的赋值也会复制该值,因此现在有三个副本在浮动。地址4是这个新实例中互斥锁指针的地址。
英文:
Address 1 is the address of the pointer to your mutex. Address 2 is the address of your mutex. That is, 2 points to where the mutex bits live, 1 points to where the pointer in 2 lives. Printing with %T
instead of %p
will show you the types of the values are different.
The append
actually copies your struct. The struct instance is a value just like an int
is; when you append a struct to the list, you are actually copying the values of each field inside it.
Value semantics for structs are widely used in C and Go (and also present in e.g. C# ValueTypes), but less common in, for example, Java, JavaScript, or Python. They mean you sometimes have to think about whether things are pointers or not, but they can save you some mistakes from accidentally making a change in one place that has an effect somewhere else (aliasing), and reduce the number of pointers the garbage collector has to follow.
Address 3 is the address of the mutex pointer in the copy of your struct created by append
.
The assignment to mystructinstance2
also copies the value, so now there are three copies of it floating around. Address 4 is the address of the mutex pointer in this new instance.
答案3
得分: 1
你想要的翻译如下:
你想要
k := elem.structList[0].mut
p1 := &*k
或者简单地,
p2 := &*elem.structList[0].mut
例如,
package main
import (
"fmt"
"sync"
)
type myStruct struct {
mut *sync.RWMutex
}
type arrayOfMyStruct struct {
structList []myStruct
}
func main() {
k := &sync.RWMutex{}
myStructInstance := myStruct{k}
fmt.Printf("%p\n", &*k)
var listStruct []myStruct
listStruct = append(listStruct, myStructInstance)
test := &arrayOfMyStruct{listStruct}
test.access()
}
func (elem *arrayOfMyStruct) access() {
k := elem.structList[0].mut
p1 := &*k
fmt.Printf("%p\n", p1)
p2 := &*elem.structList[0].mut
fmt.Printf("%p\n", p2)
}
输出:
0xc4200142c0
0xc4200142c0
0xc4200142c0
英文:
You want
k := elem.structList[0].mut
p1 := &*k
or, simply,
p2 := &*elem.structList[0].mut
For example,
package main
import (
"fmt"
"sync"
)
type myStruct struct {
mut *sync.RWMutex
}
type arrayOfMyStruct struct {
structList []myStruct
}
func main() {
k := &sync.RWMutex{}
myStructInstance := myStruct{k}
fmt.Printf("%p\n", &*k)
var listStruct []myStruct
listStruct = append(listStruct, myStructInstance)
test := &arrayOfMyStruct{listStruct}
test.access()
}
func (elem *arrayOfMyStruct) access() {
k := elem.structList[0].mut
p1 := &*k
fmt.Printf("%p\n", p1)
p2 := &*elem.structList[0].mut
fmt.Printf("%p\n", p2)
}
Output:
0xc4200142c0
0xc4200142c0
0xc4200142c0
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论