Today I’ll continue where I left off yesterday, talking about…
Method expressions
…
Similarly, the expression
(*T).Mp
yields a function value representing Mp with signature
func(tp *T, f float32) float32
The key difference to notice between this example and yesterday’s is that the first argument (that of the receiver) is a pointer here, but was not a pointer in the previous example:
func(tv T, a int) int // First argument of type T, not a pointer
func(tp *T, f float32) float32 // First argument of type *T, a pointer
For a method with a value receiver, one can derive a function with an explicit pointer receiver, so
(*T).Mv
yields a function value representing Mv with signature
func(tv *T, a int) int
That is to say, we can get a “pointer” version of the first example if we want to…
func(tv T, a int) int // First argument of type T, not a pointer
func(tp *T, f float32) float32 // First argument of type *T, a pointer
func(tv *T, a int) int // Now the first argument of type *T, as well
Such a function indirects through the receiver to create a value to pass as the receiver to the underlying method; the method does not overwrite the value whose address is passed in the function call.
That to say, using the (*T).Mv
construct does not render you suddenly able to change the values of the receiver within the method:
type T struct {
a int
}
func (t T) Mv(a int) { t.a = a } // value receiver
func (t *T) Mp(a int) { t.a = a } // pointer receiver
var t T
fp := (*T).Mp
fp(&t, 4)
fmt.Println(t) // Prints 4; the pointer receiver allows modifying the receiver
fvp := (*T).Mv
fvp(&t, 5)
fmt.Println(t) // Prints 4; value receivers cannot be modified within the method
The final case, a value-receiver function for a pointer-receiver method, is illegal because pointer-receiver methods are not in the method set of the value type.
See a full example in the playground.
Quotes from The Go Programming Language Specification Version of August 2, 2023