Golang中指针内容的差异

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?

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
", mystructinstance2.mut)

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.

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
", &*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
", p1)
    p2 := &*elem.structList[0].mut
    fmt.Printf("%p
", p2)
}

Output:

0xc4200142c0
0xc4200142c0
0xc4200142c0