golang dispatch method call according to a map[string]somestruct

一曲冷凌霜 提交于 2021-01-29 07:51:51

问题


Assuming I have lots of functions or methods with receiver, each of which has different type of parameters. I want to use table-driven method to dispatch function or method call. So I'll construct a table like this:

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

No matter what command I receive, I'll always use one statement like table[some-command-name](parameter1, parameter2, ...) instead of using the ugly switch-case structure.

Is this possible ? That different methods have different number of parameters is a problem ?


回答1:


There are two possible ways. One is through reflection, that is reflect package and in particular the Call method. The second one is through function values and closures. I would not recommend the first solution, reflection is generally discouraged because it is complicated, error prone and expensive.

Solution through 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)
    }
}

Solution through function closures (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()
    }
}


来源:https://stackoverflow.com/questions/57017441/golang-dispatch-method-call-according-to-a-mapstringsomestruct

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!