Golang中指针内容的差异

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

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

huangapple
  • 本文由 发表于 2017年8月21日 06:39:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/45787405.html
匿名

发表评论

匿名网友

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

确定