sizeof.blog

Value vs Pointer Receivers in Go - Why It Matters for Interfaces

Go is a language that values simplicity, but sometimes this simplicity becomes confusing like in value vs pointer receivers.

Method Receiver

Methods are functions which are bounded to a type. They come with receiver which can be either value receiver or pointer receiver, value receiver gets a copy and pointer receiver gets a reference.

type Circle struct {
	radius int
}

// Value receiver
func (c Circle) Area() int {
	return c.radius * c.radius
}

// Pointer receiver
func (c *Circle) Scale(factor int) {
	c.radius *= factor
}
Value Receiver (c Circle) Pointer Receiver (*c Circle)
Copies the value. Uses the same value (reference).
Can not modify the original. Can modify the original struct.
Works with both values and pointers. Only works with pointers.
Good for small structs, no mutation. Good for large structs or needing mutation.



Interfaces

We know that a type T implements an interface only if T has all the methods.

Here comes confusing part - If any method has a pointer receiver, T itself does not implement the interface, but *T does.

type Shape interface {
	Area() int
	Perimeter() int
}

type Circle struct {
	radius int
}

// Mixed Receivers
func (c Circle) Area() int {
	return c.radius * c.radius
}

func (c *Circle) Perimeter() int {
	return 2 * c.radius
}

var s1 Shape = Circle{radius: 5}   // Error
var s2 Shape = &Circle{radius: 5} // Works


Circle has Area, but not Perimeter because it's pointer receiver only.

*Circle has both.

According to Go Documentation we should pick one for all methods:

Recommendations

Use value receivers when:

  • Your type is small
  • Methods are read-only

Use pointer receivers when:

  • Your type is large
  • You modify the receiver
  • Any method needs a pointer → make all pointer receivers for consistency

Cheers 👯‍♀️