Skip to main content
eLearner.app
Module 5 · Lesson 2 of 522/50 in the course~14 min
Module lessons (2/5)

Methods: value vs pointer receiver

A method in Go is a function with a receiver: a special parameter declared between func and the method name, which binds the method to a type. There are no classes: methods can be defined on any named type declared in the current package.

Syntax

Go
type Person struct {
    Name string
}

func (p Person) Greet() string {
    return "ciao " + p.Name
}

p := Person{Name: "Ada"}
fmt.Println(p.Greet())   // "ciao Ada"

The receiver p Person makes Greet a method of Person. Inside the method, p is a variable like any other.

Value receiver vs pointer receiver

Go
// VALUE receiver: operates on a COPY of the value
func (p Person) NameUpper() string {
    return strings.ToUpper(p.Name)
}

// POINTER receiver: operates on the original value, can mutate it
func (p *Person) Rename(n string) {
    p.Name = n
}

With a pointer receiver you can modify the receiver and the changes are visible outside the method. With a value receiver you cannot — you'd only modify the local copy.

Go
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name)   // "Grace" — change is visible

When to use a pointer receiver

Practical rules, in order of priority:

  1. You must modify the receiver → pointer receiver. Mandatory.
  2. The struct is large (dozens of fields, arrays inside) → pointer receiver to avoid expensive copies.
  3. Consistency: if AT LEAST one method on the type has a pointer receiver, use a pointer receiver for the others too. A very important convention for interfaces (Module 6).
  4. Small, immutable, "value" types (time.Time, complex numbers, small structs) → value receiver, more readable.

Methods on non-struct types

You can define methods on any NAMED type declared in your package:

Go
type Celsius float64

func (c Celsius) ToFahrenheit() float64 {
    return float64(c)*9/5 + 32
}

t := Celsius(20)
fmt.Println(t.ToFahrenheit())  // 68

You cannot define them on types from other packages (e.g. int, string): you must first create a local named type.

Try it

Exercise#go.m5.l2.e1
Attempts: 0Loading…

Add a Greet() string method (value receiver) to Person that returns 'ciao <Name>'.

Loading editor…
Show hint

Receiver in parentheses BEFORE the method name.

Solution available after 3 attempts

Exercise#go.m5.l2.e2
Attempts: 0Loading…

Add a Rename(n string) method with a POINTER receiver that changes p.Name.

Loading editor…
Show hint

Pointer receiver: `(p *Person)`.

Solution available after 3 attempts

Quiz#go.m5.l2.e3
Ready

When should you use a pointer receiver (p *T)?

Go
func (t ?T) M() { ... }
Answer options

Recap

  • Method = function with a receiver: func (r T) Name(...) ... { ... }.
  • Value receiver: operates on a copy; Pointer receiver: operates on the original.
  • Go performs the T*T conversion automatically at the call site.
  • Pointer receiver when: mutation + large struct + consistency with other methods of the type.
  • Never mix value and pointer receivers on the same type.
  • Methods go on NAMED types in the current package (including non-struct).