我很好奇Go是否可行。我有一个有多种方法的类型。是否有可能有一个函数,它接受一个方法,并可以为类型调用它?
以下是我想要的一个小例子:
package main
import (
"fmt"
)
type Foo int
func (f Foo) A() {
fmt.Println("A")
}
func (f Foo) B() {
fmt.Println("B")
}
func (f Foo) C() {
fmt.Println("C")
}
func main() {
var f Foo
bar := func(foo func()) {
f.foo()
}
bar(A)
bar(B)
bar(C)
}
Go think type Foo
有一个名为foo()
的方法,而不是用传入的方法名替换它。
答案 0 :(得分:28)
是的,这是可能的。您有2(3)个选项:
表达式Foo.A
产生的函数等效于A
,但显式接收器作为其第一个参数;它有签名func(f Foo)
。
var f Foo
bar := func(m func(f Foo)) {
m(f)
}
bar(Foo.A)
bar(Foo.B)
bar(Foo.C)
这里方法接收器是显式的。您只能将方法名称(及其所属类型)传递给bar()
,并且在调用时,您必须传递实际的接收者:m(f)
。
按预期输出(在Go Playground上试试):
A
B
C
如果f
是Foo
类型的值,则表达式f.A
会生成类型为func()
的函数值,其隐式接收器值为f
。
var f Foo
bar := func(m func()) {
m()
}
bar(f.A)
bar(f.B)
bar(f.C)
请注意,此处方法接收器是隐式的,它与传递给bar()
的函数值一起保存,因此在未明确指定它的情况下调用它:m()
。
输出相同(在Go Playground上尝试)。
不如以前的解决方案(性能和安全性"),但您可以将方法的名称作为string
值传递,然后使用reflect
包以通过该名称调用方法。它看起来像这样:
var f Foo
bar := func(name string) {
reflect.ValueOf(f).MethodByName(name).Call(nil)
}
bar("A")
bar("B")
bar("C")
在Go Playground上尝试此操作。
答案 1 :(得分:0)
您还可以将@icza列出的“方法值”选项用于不同的接收器。
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
}
答案 2 :(得分:0)
我想要一个不使用 map[string]func() 来包含状态方法的状态机类型组件。我的代码允许运行方法 这是一个简单的 for 循环,当 pfunc == nil
时中断type Foo struct {
name string
idx int
}
type X func(*Foo) X
func (f *Foo) A() X {
f.name += fmt.Sprintf(" A[%d]", f.idx)
fmt.Println(f.name)
if f.idx > 10 {
fmt.Println("Foo is complete!")
return nil
} else {
f.idx += 1
return (*Foo).B
}
}
func (f *Foo) B() X {
f.name += fmt.Sprintf(" B[%d]", f.idx)
fmt.Println(f.name)
f.idx += 2
return (*Foo).C
}
func (f *Foo) C() X {
f.name += fmt.Sprintf(" C[%d]", f.idx)
fmt.Println(f.name)
f.idx += 3
return (*Foo).A
}
func main() {
bar := &Foo{"Ready!", 0}
pfunc := (*Foo).A
except := 1
for pfunc != nil && except < 10 {
pfunc = pfunc(bar)
except += 1
}
}
输出:
准备好! A[0]
准备好! A[0] B[1]
准备好! A[0] B[1] C[3]
准备好! A[0] B[1] C[3] A[6]
准备好! A[0] B[1] C[3] A[6] B[7]
准备好! A[0] B[1] C[3] A[6] B[7] C[9]
准备好! A[0] B[1] C[3] A[6] B[7] C[9] A[12]
Foo 完成了!