登录
首页 >  Golang >  Go问答

使用Go调用Mapsome结构的Dispatch方法

来源:stackoverflow

时间:2024-03-13 14:54:25 201浏览 收藏

小伙伴们对Golang编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《使用Go调用Mapsome结构的Dispatch方法》,就很适合你,本篇文章讲解的知识点主要包括。在之后的文章中也会多多分享相关知识点,希望对大家的知识积累有所帮助!

问题内容

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

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 方法。第二个是通过函数值和闭包。我不会推荐第一个解决方案,通常不鼓励反射,因为它很复杂、容易出错并且成本高昂。

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

    }

}

本篇关于《使用Go调用Mapsome结构的Dispatch方法》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>