Search code examples
pointersgostructdereference

Does dereferencing a struct return a new copy of struct?


Why when we reference struct using (*structObj) does Go seem to return a new copy of structObj rather than return the same address of original structObj? This might be some misunderstanding of mine, so I seek clarification

package main

import (
    "fmt"
)

type me struct {
    color string
    total int
}

func study() *me {
    p := me{}
    p.color = "tomato"
    fmt.Printf("%p\n", &p.color)
    return &p
}

func main() {
    p := study()
    fmt.Printf("&p.color = %p\n", &p.color)

    obj := *p
    fmt.Printf("&obj.color = %p\n", &obj.color)
    fmt.Printf("obj = %+v\n", obj)

    p.color = "purple"
    fmt.Printf("p.color = %p\n", &p.color)
    fmt.Printf("p = %+v\n", p)
    fmt.Printf("obj  = %+v\n", obj)

    obj2 := *p
    fmt.Printf("obj2 = %+v\n", obj2)
}

Output

0x10434120
&p.color = 0x10434120
&obj.color = 0x10434140   //different than &p.color!
obj = {color:tomato total:0}
p.color = 0x10434120
p = &{color:purple total:0}
obj  = {color:tomato total:0}
obj2 = {color:purple total:0} // we get purple now when dereference again

Go playground


Solution

  • When you write

    obj := *p
    

    You are copying the value of struct pointed to by p (* dereferences p). It is similar to:

    var obj me = *p
    

    So obj is a new variable of type me, being initialized to the value of *p. This causes obj to have a different memory address.

    Note that obj if of type me, while p is of type *me. But they are separate values. Changing a value of a field of obj will not affect the value of that field in p (unless the me struct has a reference type in it as a field, i.e. slice, map or channels. See here and here.). If you want to bring about that effect, use:

    obj := p
    // equivalent to: var obj *me = p
    

    Now obj points to the same object as p. They still have different addresses themselves, but hold within them the same address of the actual me object.