There was no livestream today, as I was a bit under the weather. I intend to be back live streaming next Monday as usual
Method expressions
If
Mis in the method set of typeT,T.Mis a function that is callable as a regular function with the same arguments asMprefixed by an additional argument that is the receiver of the method.MethodExpr = ReceiverType "." MethodName . ReceiverType = Type .
This might seem a bit mundane at first. But there’s something subtle, going on here, that surprises most people when they first encounter it.
Consider a struct type
Twith two methods,Mv, whose receiver is of typeT, andMp, whose receiver is of type*T.type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t TThe expression
T.Mvyields a function equivalent to
Mvbut with an explicit receiver as its first argument; it has signaturefunc(tv T, a int) int
If you’re like most, you’re so accustomed to calling methods on instantiated values, that you’ve never considered what the full function signature of a method looks like when separated from the receiver—or that the concept even makes sense.
But that’s essentially what we’ve done here:
x := T.Mv
notMv := func(T, int) int {
return 0
}
x = notMv // This assignment is valid, because notMv is of the same type as x, aka `func(T, int) int`
That function may be called normally with an explicit receiver, so these five invocations are equivalent:
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
Tomorrow we’ll complete the discussion of the second half of the example, with the pointer receiver.
Quotes from The Go Programming Language Specification Version of August 2, 2023