golang中指针内容的差异

时间:2017-08-20 22:39:31

标签: go

考虑结构和指针引用示例的以下代码。

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
}

为什么地址2 3和4不同?他们不应该一样吗?

3 个答案:

答案 0 :(得分:1)

这是因为mut中的myStruct已经是指针*sync.RWMutex,所以当你这样做时:

&mystructinstance2.mut

您实际上正在获取一个指向mut的新指针,该指针是指向**sync.RWMutex之类的互斥锁的指针。只需删除打印语句中的&即可。当您使用k := &sync.RWMutex{}创建互斥锁时,它已经是指针,因此您不应该在该变量之后的任何地方使用&,否则它将创建指向该指针的新指针。您还可以使用k := new(sync.RWMutex)创建指向新互斥锁的指针。

您可以在Printf上使用%p来打印指针地址:

fmt.Printf("%p\n", mystructinstance2.mut)

答案 1 :(得分:1)

地址1是指向互斥锁的指针的地址。地址2是互斥锁的地址。也就是说,互斥体位居住的位置为2点,2位指针位于1位置。使用%T代替%p进行打印会显示值的类型不同。

append实际上复制了你的结构。 struct实例是一个像int那样的值;当您将结构附加到列表时,实际上是在复制其中每个字段的值。

结构的值语义广泛用于C和Go(并且也存在于例如C#ValueTypes中),但在例如Java,JavaScript或Python中不太常见。它们意味着你有时候不得不考虑事物是否是指针,但是它们可以避免一些错误,因为它意外地在一个地方做了一个改变而在其他地方产生了影响(别名),并且减少了垃圾收集器指针的数量。跟随。

地址3是由append创建的结构副本中的互斥锁指针的地址。

mystructinstance2的分配也会复制该值,因此现在有三个副本浮动。地址4是此新实例中互斥锁指针的地址。

答案 2 :(得分: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