Kir
Kir

Reputation: 8111

Initializing a struct as a pointer or not

type Vertex struct {
    X, Y float64
}

func main() {
    v := Vertex{3, 4}
    fmt.Println(v)

    d := &Vertex{3, 4}
    fmt.Println(d)
}

http://play.golang.org/p/XluyUHL2y7

What's the difference between these two ways to initialize a Vertex struct?

I know that second one is allocation with pointer, but I can't see any difference of this solution in practice.

Upvotes: 8

Views: 2307

Answers (2)

deft_code
deft_code

Reputation: 59269

TL;DR There is no difference1. Whether a variable is allocated on the stack or heap depends on its usage.

I did a deep dive on the the assembly Go generates from various initialization and calling cases. The assembly generated between v and b is nearly the same. Of particular note, d is not allocated on the stack1.

What determines whether a variable is heap allocated or stack allocated is how it is used. Passing a passing a pointer into a function that only used the parameter as a value will not force a variable to be heap allocated. But even this isn't guaranteed, the spec allows any Go compiler to freely move variables between the stack an heap as needed for optimization or code generation. Go abstracts away Heap vs Stack just as C/C++ abstracts away RAM vs Register.

http://play.golang.org/p/vJQvWPTGeR

type Vertex struct {
    X, Y float64
}

func PrintPointer(v *Vertex) {
    fmt.Println(v)
}

func PrintValue(v *Vertex) {
    fmt.Println(*v)
}

func main() {
    a := Vertex{3, 4} // not allocated
    PrintValue(&a)

    b := &Vertex{3, 4} // not allocated
    PrintValue(b)

    c := Vertex{3, 4} // allocated
    PrintPointer(&c)

    d := &Vertex{3, 4} // allocated
    PrintPointer(d)
}

1: technically not true, but would be true if fmt.Println(*d) had been used instead. I cheated a little to answer the question I think you meant to ask.

Upvotes: 4

distributed
distributed

Reputation: 386

In both cases, a Vertex struct is intialized in the same way.

The first expression returns value which is an initialized Vertex struct. With 6g's alignment rules, this means that you will get 8+8 = 16 bytes worth of Vertex struct, since every float64 is 8 bytes in size. The second expression allocates memory, enough for 8+8 = 16 bytes, uses it as a Vertex struct, initializes it and returns a pointer, which will be 4 or 8 bytes in size, depending on your architecture.

There are a number of differences in practice. The method sets of these two values, the Vertex struct and the *Vertex pointer, may be different. Depending on how often you need to pass around the Vertex struct, it might or might not be more efficient to pass a pointer to it. If you pass a Vertex struct to a function, the function gets a copy and your Vertex struct will never be modified. If you pass a *Vertex, your underlying Vertex might be changed. This might or might not be your intention :)

Upvotes: 3

Related Questions