I\'m curious if this is possible in Go. I have a type with multiple methods. Is it possible to have a function which takes a method argument and then call it for the type?
Yes, it's possible. You have 2 (3) options:
The expression Foo.A
yields a function equivalent to A
but with an explicit receiver as its first argument; it has signature func(f Foo)
.
var f Foo
bar := func(m func(f Foo)) {
m(f)
}
bar(Foo.A)
bar(Foo.B)
bar(Foo.C)
Here the method receiver is explicit. You only pass the method name (with the type it belongs to) to bar()
, and when calling it, you have to pass the actual receiver: m(f)
.
Output as expected (try it on the Go Playground):
A
B
C
If f
is a value of type Foo
, the expression f.A
yields a function value of type func()
with implicit receiver value f
.
var f Foo
bar := func(m func()) {
m()
}
bar(f.A)
bar(f.B)
bar(f.C)
Note that here the method receiver is implicit, it is saved with the function value passed to bar()
, and so it is called without explicitly specifying it: m()
.
Output is the same (try it on the Go Playground).
Inferior to previous solutions (both in performance and in "safeness"), but you could pass the name of the method as a string
value, and then use the reflect package to call the method by that name. It could look like this:
var f Foo
bar := func(name string) {
reflect.ValueOf(f).MethodByName(name).Call(nil)
}
bar("A")
bar("B")
bar("C")
Try this on the Go Playground.
You could also use the “method values” option listed by @icza with different receivers.
package main
import "fmt"
type Foo int
type Goo int
func (f Foo) A() { fmt.Println("A") }
func (f Foo) B() { fmt.Println("B") }
func (g Goo) A() { fmt.Println("A") }
func main() {
//Method values with receiver f
var f Foo
bar2 := func(m func()) { m() }
bar2(f.A) //A
bar2(f.B) //B
//Method values with receivers f and g
var g Goo
bar2(f.A) //A
bar2(g.A) //A
}