根据 map[string]somestruct 调用 golang 调度方法

标签 go closures map-function

假设我有很多带有接收器的函数或方法,每个函数或方法都有不同类型的参数。我想使用表驱动方法来调度函数或方法调用。所以我将构建一个这样的表:

type command struct {
   name string
   handler func(parameter ...interface{}) // I don't know whether to use `...interface{}` is correct
}

table := map[string]command { ... }

func (c command)foo(f1 int, f2 string) {}
func (c command)bar(b1 bool, b2 int, b3 string) {}
// methods and so on

无论我收到什么命令,我总是会使用像 table[some-command-name](parameter1, parameter2, ...) 这样的语句,而不是使用丑陋的 switch-case结构。

这可能吗?不同的方法有不同数量的参数是个问题吗?

最佳答案

有两种可能的方法。一种是通过反射,即reflect 包,特别是Call 方法。第二个是通过函数值和闭包。我不会推荐第一种解决方案,通常不鼓励使用反射,因为它很复杂、容易出错且代价高昂。

反射(reflection)解决(https://play.golang.org/p/3b5I77QMsFI):

type command struct {
    name    string
    handler reflect.Value
    args    []reflect.Value
}

var table = map[string]command{
    "Foo": {
        name:    "Foo",
        handler: reflect.ValueOf(foo),
        args: []reflect.Value{
            reflect.ValueOf(1),
            reflect.ValueOf("hello"),
        },
    },
    "Bar": {
        name:    "Bar",
        handler: reflect.ValueOf(bar),
        args: []reflect.Value{
            reflect.ValueOf(true),
            reflect.ValueOf(5),
            reflect.ValueOf("hello"),
        },
    },
}

func foo(f1 int, f2 string) {
    fmt.Println("Foo:", f1, f2)
}
func bar(b1 bool, b2 int, b3 string) {
    fmt.Println("Bar:", b1, b2, b3)
}

func main() {
    for name, command := range table {
        fmt.Println("Running", name)
        command.handler.Call(command.args)
    }
}

通过函数闭包解决(https://play.golang.org/p/8fM86lxalq1):

type MyFuncType func()

type command struct {
    name    string
    handler MyFuncType
}

var table = map[string]command{
    "Foo": {
        name:    "Foo",
        handler: fooClosure(1, "hello"),
    },
    "Bar": {
        name:    "Bar",
        handler: barClosure(true, 5, "hello"),
    },
}

func foo(f1 int, f2 string) {
    fmt.Println("Foo:", f1, f2)
}

func fooClosure(f1 int, f2 string) MyFuncType {
    return func() {
        foo(f1, f2)
    }
}

func bar(b1 bool, b2 int, b3 string) {
    fmt.Println("Bar:", b1, b2, b3)
}

func barClosure(b1 bool, b2 int, b3 string) MyFuncType {
    return func() {
        bar(b1, b2, b3)
    }
}

func main() {
    for name, command := range table {
        fmt.Println("Running", name)
        command.handler()
    }
}

关于根据 map[string]somestruct 调用 golang 调度方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57017441/

相关文章:

javascript - 这个闭包是在全局范围内吗?

go - Docker 返回 "json: cannot unmarshal string into Go value of type []string"

go - 调用包的函数而不使用其包名称?

json - 使用\u0000\x00 去 json.Unmarshal key

Swift:闭包是否引用常量或变量?

python - 将字符串映射到对列表

firebase - 访问 Firestore 需要项目 ID 错误

php - 在对象属性中存储 PHP 闭包是否有任何已知的副作用?

python - 对 DataFrame 中的 NaN 行应用 Map,Python 3.6

haskell - 将函数映射到字符串