Learn Go← Dashboard

Attach behavior to types — value vs pointer receivers.

Methods and Receivers

A method is a function with a special "receiver" argument written before the name. It's how you attach behavior to types in Go.

type Rect struct{ W, H float64 }

func (r Rect) Area() float64 {
    return r.W * r.H
}

That (r Rect) is the receiver — read it as "on a Rect, called r".

go playground
Loading...

Value vs pointer receivers

You can declare a method on either a value or a pointer:

func (r Rect) Area() float64  { ... }   // value receiver — gets a copy
func (r *Rect) Scale(k float64) { ... } // pointer receiver — can modify r

Rules of thumb:

  • Use a pointer receiver if the method needs to modify the receiver, or if the struct is large enough that copying is wasteful, or if other methods on the type already use pointer receivers (be consistent).
  • Use a value receiver for small, immutable types (time.Time, Point).
go playground
Loading...

Go automatically takes the address when needed: c.Inc() works even though Inc expects *Counter. (You can also write (&c).Inc() — same thing.)

Methods aren't limited to structs

You can define methods on any named type, including aliases of built-in types:

go playground
Loading...

You cannot define methods on types you don't own (e.g. int, or another package's types). Wrap them in your own named type first.

A subtle interface trap

Method sets matter when you put a value behind an interface:

  • A value of type T has only the methods defined with value receivers.
  • A pointer *T has both value-receiver and pointer-receiver methods.
type Greeter interface{ Greet() }

type Dog struct{}
func (d *Dog) Greet() {}     // pointer receiver only

var g Greeter = Dog{}        // ✗ compile error: Dog{} doesn't have Greet()
var g Greeter = &Dog{}       // ✓ OK

If a method "doesn't exist" when you assign to an interface, double-check whether you're using a value or a pointer.

Which receiver should `func (c Counter) Inc()` use to actually increment the counter?