What is the difference between passing a struct and pointer of the struct, are they not both pointers?

When you pass a pointer as an argument, what happens under the hood is that a copy of that pointer is created and passed to the underlying function. It should not be confused with pass-by-reference.

Let's look at an example to better grasp it:

package main

import (
    "fmt"
)

type Point struct {
    x int
    y int
}

func (p Point) String() string {
    return fmt.Sprintf("(%d, %d)", p.x, p.y)
}

func modifyValue(point Point) {
    point.x += 10
}

func modifyPointer(point *Point) {
    point.x = 5
    point.y = 5
}

func modifyReference(point *Point) {
    point = &Point{5, 5}
}

func main() {
    p := Point{0, 0}
    fmt.Println(p) // prints (0, 0)
    
    modifyValue(p)
    fmt.Println(p) // prints (0, 0)
    
    modifyPointer(&p)
    fmt.Println(p) // prints (5, 5)
    
    p = Point{0, 0}
    modifyReference(&p)
    fmt.Println(p) // prints (0, 0)
}

What happens inside the modifyValue function is that a totally different instance of a Point structure is modified, so the value passed when calling the function is unaffected.

In the second example, a pointer to the structure is passed so the fields of the structure can be modified in a way that is visible from outside.

The most interesting point is made by the last function, modifyReference. If you are familiar with the pass by reference paradigm available in other languages you would expect to be able to modify the referenced object altogether, but this doesn't happen. It's because you're modifying a copy of the pointer passed as argument.

You may wonder, if everything is passed by value, when should you pass pointers and when values. Passing values assures the caller function that the passed structure cannot suffer any changes, so when you need this behaviour, go for the value. The downside of this is that a copy of the entire object is made and, if it is too big, memory becomes a concern.

If you're passing a big structure as an argument, using a pointer is better because it saves space, but you lose the guarantee that the object won't suffer any changes.


Passing struct to function argument makes copy of values. And passing pointer of struct doesn't. So passing struct can't update field value.

package main

import (
    "fmt"
)

type Foo struct {
    value int
}

func PassStruct(foo Foo) {
    foo.value = 1
}

func PassStructPointer(foo *Foo) {
    foo.value = 1
}

func main() {
    var foo Foo

    fmt.Printf("before PassStruct: %v\n", foo.value)
    PassStruct(foo)
    fmt.Printf("after PassStruct: %v\n", foo.value)

    fmt.Printf("before PassStructPointer: %v\n", foo.value)
    PassStructPointer(&foo)
    fmt.Printf("after PassStructPointer: %v\n", foo.value)
}

https://play.golang.org/p/AM__JwyaJa

Tags:

Pointers

Go