Methods / Receivers
In Go, you can associate functions with specific types — these are called "methods." Methods are defined using a special parameter called a "receiver." Understanding the difference between value receivers and pointer receivers is essential.
Syntax
// Value receiver (operates on a copy; the original value is not modified)
func (receiverVar TypeName) MethodName(args) ReturnType {
// You can read the receiver's fields, but changes won't affect the original.
}
// Pointer receiver (can modify the original value)
func (receiverVar *TypeName) MethodName(args) ReturnType {
// Changes to the receiver's fields are reflected in the original.
}
// Calling a method
obj := TypeName{}
obj.MethodName() // Go automatically converts between value and pointer as needed.
ptr := &TypeName{}
ptr.MethodName()
Value Receiver vs. Pointer Receiver
| Type | Description |
|---|---|
| Value receiver (T) | Receives a copy of the receiver. Suited for read-only methods that do not modify the original value. |
| Pointer receiver (*T) | Receives a pointer to the receiver. Use this when you need to modify the original value or want to avoid the cost of copying. |
| Automatic conversion | Go automatically takes the address or dereferences the value as needed at the call site. |
| Interface implementation | Methods defined with a pointer receiver can only satisfy an interface when the type is a pointer type. |
Sample Code
package main
import (
"fmt"
"math"
)
type Circle struct {
Radius float64
}
// Value receiver: operates on a copy of c (the original Circle is not changed).
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// Pointer receiver: can modify the original Circle.
func (c *Circle) Scale(factor float64) {
c.Radius *= factor
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r *Rectangle) Resize(w, h float64) {
r.Width = w
r.Height = h
}
// Returns a string representation (implements the Stringer interface)
func (c Circle) String() string {
return fmt.Sprintf("Circle(radius=%.2f)", c.Radius)
}
func main() {
c := Circle{Radius: 5.0}
fmt.Println("Circle:", c)
fmt.Printf("Area: %.2f\n", c.Area())
fmt.Printf("Perimeter: %.2f\n", c.Perimeter())
// Calling a pointer receiver method on a value automatically takes its address.
c.Scale(2.0) // equivalent to (&c).Scale(2.0)
fmt.Printf("Radius after scaling by 2: %.2f\n", c.Radius)
fmt.Println()
rect := Rectangle{Width: 4, Height: 6}
fmt.Printf("Rectangle area: %.2f\n", rect.Area())
rect.Resize(10, 3)
fmt.Printf("After resize: width=%.2f, height=%.2f\n", rect.Width, rect.Height)
fmt.Printf("Area after resize: %.2f\n", rect.Area())
}
Notes
In Go, methods can be added not only to structs but to any named type defined in the same package, including aliases of built-in types. Mixing pointer and value receivers on the same type is allowed, but requires care when implementing interfaces. In general, it is recommended to use pointer receivers consistently.
If a method is defined with a pointer receiver, only the pointer type (*T) satisfies that interface. The value type (T) does not. Assigning a value type to an interface variable in this case will result in a compile error.
For struct definitions, see struct. For combining methods with interfaces, see interface.
If you find any errors or copyright issues, please contact us.