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 }
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.
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.
Passing structs by value is useful when:
Example:
func (p Person) GetName() string { return p.Name }
Here, GetName only reads the Name field and returns a string without modifying the struct’s state.
Passing structs by pointer is beneficial when:
Example:
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 }
In this case, UpdateName directly modifies the Name field of the original struct, which is more efficient than creating a copy.
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.
The above is the detailed content of The difference between pointers and values on methods. For more information, please follow other related articles on the PHP Chinese website!