Value Receiver vs Pointer Receiver in Go: Key Differences and Usage
value receiver gets a copy of the data, so changes inside the method don't affect the original value. A pointer receiver gets the address of the data, allowing the method to modify the original value directly.Quick Comparison
Here is a quick side-by-side comparison of value receivers and pointer receivers in Go.
| Aspect | Value Receiver | Pointer Receiver |
|---|---|---|
| Data Access | Works on a copy of the value | Works on the original value via its address |
| Modification Effect | Changes do NOT affect the original | Changes affect the original value |
| Memory Use | Copies data, can be costly for large structs | No copy, more efficient for large structs |
| Method Call | Can be called on both value and pointer | Can be called on both pointer and value (if addressable) |
| Use Case | For small, immutable data | For large data or when mutation is needed |
Key Differences
A value receiver means the method operates on a copy of the struct. This means any changes made inside the method do not affect the original struct outside the method. It is like making a photocopy of a document and writing on the copy; the original stays the same.
On the other hand, a pointer receiver means the method receives the memory address of the struct. This allows the method to modify the original struct directly. It is like having the original document and writing on it, so the changes are visible everywhere.
Using pointer receivers is more efficient for large structs because it avoids copying the entire data. Also, pointer receivers are necessary when you want the method to change the struct's fields. Value receivers are simpler and safe when you only need to read data or work with small structs.
Code Comparison
package main import "fmt" type Counter struct { Count int } // Value receiver method func (c Counter) Increment() { c.Count++ fmt.Println("Inside Increment (value receiver):", c.Count) } func main() { c := Counter{Count: 1} c.Increment() fmt.Println("After Increment call:", c.Count) }
Pointer Receiver Equivalent
package main import "fmt" type Counter struct { Count int } // Pointer receiver method func (c *Counter) Increment() { c.Count++ fmt.Println("Inside Increment (pointer receiver):", c.Count) } func main() { c := Counter{Count: 1} c.Increment() fmt.Println("After Increment call:", c.Count) }
When to Use Which
Choose value receivers when your method does not need to modify the struct and the struct is small, like simple data or immutable values. This keeps your code safe from accidental changes.
Choose pointer receivers when your method needs to change the struct's fields or when the struct is large and copying it would be inefficient. Pointer receivers also allow consistency if some methods need to modify the struct.