Start learning free

LESSON 189 OF 671 · GO ESSENTIALS

Methods and receivers in Go

Lesson

Go has no classes. Instead you bundle data into a struct — a group of named fields — and attach behavior to it from the outside, by writing functions with a receiver:

type Counter struct {
    count int
}

func (c Counter) Inc() {   // "(c Counter)" is the receiver
    c.count++
}

The extra (c Counter) before the name turns a plain function into a method: you call it with dot syntax, c.Inc(), and inside the method c refers to the counter it was called on. That's the whole Go replacement for classes — struct for data, methods for behavior.

But there are TWO kinds of receiver, and picking the wrong one is the most famous silent bug in Go.


The trap: a value receiver gets a COPY.

With (c Counter) — a value receiver — the method receives a copy of your struct. It increments the copy, the copy is thrown away, and your counter never changes. No error, no warning:

c := Counter{count: 0}
c.Inc()
fmt.Println(c.count)   // prints 0 — the ++ happened on a copy!

Write the receiver as a pointer instead — (c *Counter) — and the method receives the address of the ORIGINAL struct, so the mutation sticks. Calling it is no extra work: for a variable, Go automatically takes &c for you.

One thing Go will NOT do is take the address of a throwaway value. Call a pointer method directly on a struct literal and the compiler stops you:

Counter{count: 0}.IncP()   // a literal has no address
cannot call pointer method IncP on Counter

Rule of thumb: if the method needs to CHANGE the struct, the receiver must be *T. If it only reads, a value receiver is fine.


Assignment
Follow the Coding Tutorial and catch the bug in the act:

  • define Counter, a struct with one int field count,
  • attach Inc() with a value receiver (c Counter) that does c.count++,
  • attach IncP() with a pointer receiver (c *Counter) with the same body,
  • in mainFunction, create c := Counter{count: 0}, call c.Inc() and print the count — it is still 0,
  • call c.IncP() and print again — now it is 1.

The exact expected output is:

after Inc(): count = 0
after IncP(): count = 1

Hint
The two methods differ by a single character in the receiver: (c Counter) vs (c *Counter). That character decides whether the increment survives.


STEP 1 OF 9
    Ctrl + Enter to check