DEV Community

Tiago Temporin
Tiago Temporin

Posted on

The difference between pointers and values on methods

When writing methods in Go, one of the key decisions is whether to pass a struct by value or by pointer. This choice can impact performance, code behavior, and memory allocation. In this post, we’ll explore this difference with a practical example and understand when each approach is more appropriate.

Let’s start with a small struct and two methods: one where the struct is passed by value and another by pointer.

package main

import (
    "fmt"
)

type Person struct {
    Name string
    Age  int
}

// Method with struct passed by value
func (p Person) CelebrateBirthdayValue() {
    p.Age++
}

// Method with struct passed by pointer
func (p *Person) CelebrateBirthdayPointer() {
    p.Age++
}

func main() {
    person := Person{Name: "Alice", Age: 30}

    // Passing by value
    person.CelebrateBirthdayValue()
    fmt.Println("After CelebrateBirthdayValue:", person.Age) // Output: 30

    // Passing by pointer
    person.CelebrateBirthdayPointer()
    fmt.Println("After CelebrateBirthdayPointer:", person.Age) // Output: 31
}
Enter fullscreen mode Exit fullscreen mode

Difference between value and pointer

When we pass a struct by value to a method, Go creates a copy of the struct. Any changes made to the struct inside the method won’t affect the original struct because we’re working with an independent copy.

On the other hand, when we pass a struct by pointer, we pass the memory address of the original struct. This means any changes made to the struct inside the method will directly modify the original struct since we’re manipulating the same instance.

In summary:

  • By value: The method receives a copy of the struct, creating a new memory space.

  • By pointer: The method receives the memory address of the original struct, pointing to the same memory space.

Heap

When a struct is passed by value, the copy is allocated on the stack, which is generally fast and efficient. However, if the struct is large, the copy can consume significant stack memory.

When a struct is passed by pointer, the pointer itself is allocated on the stack, but the original struct might be allocated on the heap, especially if it was created using new, make, or captured by an anonymous function.

Heap allocation is more expensive in terms of allocation time and garbage collection but allows efficient manipulation of large amounts of data without copying the entire struct.

When to use each approach

By value

Passing structs by value is useful when:

  • You want to ensure the original struct is not modified.
  • The struct is small, and copying it does not significantly impact performance.
  • The method simply reads data without needing to alter the internal state.

Example:

func (p Person) GetName() string {
    return p.Name
}
Enter fullscreen mode Exit fullscreen mode

Here, GetName only reads the Name field and returns a string without modifying the struct’s state.

By pointer

Passing structs by pointer is beneficial when:

  • You need to modify the original struct.
  • The struct is large, and copying its data would be costly in terms of memory and performance.
  • You want to avoid unnecessary copies to improve code efficiency.

Example:

func (p *Person) UpdateName(newName string) {
    p.Name = newName
}
Enter fullscreen mode Exit fullscreen mode

In this case, UpdateName directly modifies the Name field of the original struct, which is more efficient than creating a copy.

Conclusion

Deciding whether to pass a struct by value or by pointer when writing methods in Go is an important choice that can affect performance, code behavior, and memory allocation.

Passing by value is useful for ensuring immutability of the struct within the method, while passing by pointer is essential for modifying the original struct and optimizing performance when working with larger structs.

Top comments (0)