Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 605
ken Avatar asked Jul 18 '16 18:07

ken


3 Answers

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.

like image 159
abhink Avatar answered Nov 17 '22 16:11

abhink


No, "assignment" always creates a copy in Go, including assignment to function and method arguments. The statement obj := *p copies the value of *p to obj.

If you change the statement p.color = "purple" to (*p).color = "purple" you will get the same output, because dereferencing p itself does not create a copy.

like image 27
JimB Avatar answered Nov 17 '22 15:11

JimB


tl;dr Dereferencing (using the * operator) in Go does not make a copy. It returns the value the pointer points to.

like image 6
Michael Dorner Avatar answered Nov 17 '22 16:11

Michael Dorner