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



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

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, ...)这样的语句,而不是使用丑陋的开关大小写结构。

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

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

通过反射解决 (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()
    }
}

对于那些在 2023 年及以后来的人......如果您出于测试目的搜索它,或者您可以保证所有函数都具有相同的参数签名,那么您可以大大简化它:

-- 注意!!这并不能解决每个参数签名不同参数的 OP 问题。然后你必须使用更像被接受的答案的东西。但是由于这是"golang中的函数调度图"的首要答案之一,我认为这将很有用

var dispatchMap = map[string]func(yourSignature type){
    "Key": funcName,
    "AnotherKey": anotherFunc,
}

所以例如...使用它来为公共包装器内的表驱动测试创建调度映射,但测试是不同的,并且并不都使用相同的函数......

func Something(t *testing.T) {
    value := "value"
    assert.Equal(t, value, "value", "Didnt Pass???")
}
func FailSomething(t *testing.T) {
    value := "nooo"
    assert.Equal(t, value, "value", "Supposed to fail!")
}
var testMap = map[string]func(t *testing.T){
    "TestSomething":     Something,
    "TestFailSomething": FailSomething,
}
func TestWrapper(t *testing.T) {
    t.Parallel()
    for name, testCommand := range testMap {
        t.Run(name, testCommand)
    }
}

相关内容

  • 没有找到相关文章

最新更新