Declaring a method
A method is a function with a receiver: an extra parameter written before the method name. The receiver ties the method to a type.
The receiver name is usually one or two letters taken from the type (c for Circle). Go does not use this or self, and style guides discourage those names.
Because Circle has a String() string method, it satisfies fmt.Stringer, and fmt.Println prints the result instead of {2}.
Value receivers and pointer receivers
A value receiver (c Circle) gets a copy. A pointer receiver (c *Circle) gets the address, so changes to fields stick.
IncByValue compiles and does nothing visible, a classic bug. If a method is meant to modify its receiver, it needs a pointer receiver.
The calls also show the two conveniences Go gives you. c.Inc() on an addressable variable is rewritten to (&c).Inc(), and p.Value() on a pointer is rewritten to (*p).Value(). You rarely write & or * just to call a method.
The automatic & needs something addressable. A map element or a composite literal is not:
m := map[string]Counter{"a": {}}
m["a"].Inc() // compile error: cannot call pointer method Inc on Counter
Counter{}.Inc() // same error: a composite literal is not addressable
Store pointers in the map (map[string]*Counter) or copy the value out, change it, and write it back.
Which receiver to choose
| Use a pointer receiver when | Use a value receiver when |
|---|---|
| The method modifies the receiver | The type is small and never modified by its methods (time.Time, a point) |
| The struct is large (copying costs) | The type is a map, func or chan (already a reference) |
The type holds a sync.Mutex or similar | You want the value to act like a primitive, safe to copy |
| Other methods on the type already use pointers |
The Go FAQ and the standard library follow one rule of thumb: be consistent. If any method needs a pointer receiver, give all methods pointer receivers, so the method set is predictable. go vet flags a struct holding a sync.Mutex that is copied through a value receiver (passes lock by value).
Method sets and interfaces
The distinction matters most for interfaces. The method set of T contains the value-receiver methods. The method set of *T contains both value- and pointer-receiver methods.
Writing Square{Side: 3} without the & in that slice fails to compile:
cannot use Square{…} (value of struct type Square) as Shape value in array or slice literal: Square does not implement Shape (method Area has pointer receiver)
The reason: an interface can hold a copy of a Square that is not addressable, so Go cannot take its address to call a pointer method. See interfaces for the rest of that story.
Methods on non-struct types
Any named type declared in your package can have methods, not only structs.
The limits: the type must be defined in the same package as the method, and its underlying type cannot be a pointer or an interface. You cannot add methods to int, string, or time.Time from your own package. Wrapping in a new named type is the Go way. String() on an integer type is also how enums get readable output; see enums with iota.
Method values and method expressions
A method bound to a specific receiver is a function value:
A method value with a value receiver copies the receiver when it is created, which is why f still says Ana. With a pointer receiver it would store the pointer and see later changes. Method values are handy for callbacks: http.HandleFunc("/", srv.handleIndex).
Common mistakes
- Value receiver on a mutating method. Compiles, silently changes a copy.
- Mixing receiver kinds. Makes it unclear whether
Tor*Tsatisfies an interface. Pick one per type. - Calling a pointer method on a nil pointer. Allowed, and the method runs with a nil receiver. It panics only when it touches a field. Some types (like a nil-safe linked list) use this on purpose; most do not expect it.
Frequently Asked Questions
What is the difference between a method and a function in Go?
A method has a receiver, written between func and the name: func (c Circle) Area() float64. You call it on a value (c.Area()), it belongs to the type's method set, and it is how a type satisfies interfaces. Otherwise it behaves like a function whose first argument is the receiver.
When should I use a pointer receiver in Go?
Use a pointer receiver when the method must modify the receiver, when the struct is large enough that copying it on every call is wasteful, or when the type contains something that must not be copied, such as a sync.Mutex. If any method of a type needs a pointer receiver, the usual advice is to make all of them pointer receivers for consistency.
Why does my type not implement the interface when the method has a pointer receiver?
Methods with a pointer receiver belong to the method set of *T, not T. So var s Shape = Square{} fails with Square does not implement Shape (method Area has pointer receiver). Assign a pointer instead: var s Shape = &Square{}.
Can you define methods on built-in types in Go?
Not directly. Methods can only be declared on named types defined in the same package. Define your own type first, type Celsius float64, and then add methods to it. You cannot add methods to int, string, or a type from another package.