What's the difference between a method value and a method expression? What does this print?
Question 101HardGo 1.22 to 1.25
type T struct{ n int }
func (t T) ShowVal() { fmt.Println("val", t.n) }
func (t *T) ShowPtr() { fmt.Println("ptr", t.n) }
func main() {
t := T{n: 1}
fv := t.ShowVal // method value: receiver COPIED now
fp := t.ShowPtr // method value: &t captured now
t.n = 2
fv() // ?
fp() // ?
fe := T.ShowVal // method expression: func(T)
fe(t) // ?
(*T).ShowPtr(&t) // method expression: func(*T)
defer t.ShowVal() // receiver evaluated at defer time
t.n = 3
}
Output:
val 1
ptr 2
val 2
ptr 2
val 2
A method value (t.ShowVal) binds the receiver immediately. With a value receiver, the struct is copied at that moment. With a pointer receiver, the pointer is captured, so later changes are visible. A method expression (T.ShowVal) produces a plain function that takes the receiver as its first argument.
defer and go statements evaluate the receiver and arguments immediately, so the deferred call prints 2, not 3. Method values usually allocate a closure when they escape, for example when stored in a struct field or passed as a callback.
More on Interfaces, Methods & Embedding
- Q99When does comparing two interface values panic? What does this print?
- Q100Does converting a value to an interface allocate? How do interfaces affect escape analysis and performance?
- Q102On which types can you declare methods? Can you add a method to
int,time.Time, a pointer type, or an interface? - Q103How does the "optional interface" (interface upgrade) pattern work? Give a stdlib example and its pitfall.
- Q104How do constraint interfaces in generics differ from ordinary interfaces?
- Q105Do methods carry over with
type B Avstype B = Avs embedding? What does this mean forsync.Mutex?