Reputation: 49
I read some strange codes which convert a method to a function whose first argument is a pointer to this method's struct.
I write an example to demonstrate it:
package main
import "fmt"
type fooS struct{}
func (s *fooS) fooF(fooArg interface{}) {
fmt.Println("fooF: ", fooArg)
}
type wowS struct {
callback func(s *fooS, fooArg interface{})
}
func main() {
wow := new(wowS)
wow.callback = (*fooS).fooF // strange
wow.callback(nil, 123)
}
The example's syntax is strange but has no error.
Can any one tell me how these codes work or give me an official document about them?
Thanks:)
Upvotes: 2
Views: 3164
Reputation:
If
M
is in the method set of typeT
,T.M
is a function that is callable as a regular function with the same arguments asM
prefixed by an additional argument that is the receiver of the method.MethodExpr = ReceiverType "." MethodName . ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
Consider a struct type
T
with 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 T
The expression
T.Mv
yields a function equivalent to
Mv
but with an explicit receiver as its first argument; it has signaturefunc(tv T, a 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)
Similarly, the expression
(*T).Mp
yields a function value representing Mp with signature
func(tp *T, f float32) float32
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 signaturefunc(tv *T, a int) int
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.
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.
Function values derived from methods are called with function call syntax; the receiver is provided as the first argument to the call. That is, given
f := T.Mv
,f
is invoked asf(t, 7)
nott.f(7)
. To construct a function that binds the receiver, use a function literal or method value.It is legal to derive a function value from a method of an interface type. The resulting function takes an explicit receiver of that interface type.
And see:
Go - difference between parameter and receiver
Is there a performance penalty for passing "this" by value in Go methods?
differences between pointer and value slice in for-range loop
Upvotes: 8