When is the receiver bound for a method value? What prints?
Question 490HardGo 1.22 to 1.25
type T struct{ n int }
func (t T) Val() { fmt.Println("val", t.n) }
func (t *T) Ptr() { fmt.Println("ptr", t.n) }
func main() {
t := T{1}
v := t.Val // method value
p := t.Ptr // method value, receiver is &t
defer t.Val()
defer t.Ptr()
t.n = 2
v()
p()
}
Output:
val 1
ptr 2
ptr 2
val 1
A method value such as t.Val evaluates and saves the receiver right away. With a value receiver, it saves a copy of t (n=1), so later changes are not seen. With a pointer receiver, it saves &t, so the call reads the current field (n=2).
defer works the same way. defer t.Val() copies the receiver at defer time and prints 1. defer t.Ptr() saves the pointer and prints 2. The deferred calls run LIFO after v() and p().
This matters when you pass obj.Method as a callback, for example http.HandleFunc("/", srv.handle) or go w.run(). With a value receiver, the callback works on a frozen snapshot, and any state it changes is lost.
More on Tricky Output & Code-Review Puzzles
- Q488Why is err != nil true here even though the function returned a nil pointer?
- Q489Why doesn't this compile, and why does Go refuse it?
- Q491Code review: why does Counter always report 0, and what else is wrong?
- Q492What happens if you add or delete map entries while ranging over the map?
- Q493Why won't m["a"].count++ compile, and what happens with a nil map?
- Q494Spot the bug: why is err nil after the if block?