有没有办法处理通用函数

时间:2020-01-15 14:47:56

标签: go generic-method reflect

我是新手,想实现一个可以接收任务的调度程序(即间隔+处理程序)。 我陷入了我应该获得处理程序的部分,因为它是一种静态语言(我无法获得通用函数签名)。 我想出了以下解决方案: 每个“处理程序”功能都将被空接口包装:

type GenericFunc interface{}
add_task(GenericFunc(my_func), p1, p2,...)

这将导致以下结构保存处理程序及其参数:

type Task struct {
   handler reflect.Value
   params []reflect.Value
   ...
}

任务执行将通过以下方式调用:

func (t *Task) execute() {
    t.handler.Call(t.params)
}

我的问题是这是处理泛型函数的正确方法,还是我缺少一种惯用的解决方案? 谢谢。

1 个答案:

答案 0 :(得分:3)

在最简单的形式中,更好的抽象方法是为处理程序使用简单的func()类型,并且如果需要参数,则调用者应传递一个捕获所需参数的闭包。因此,您根本不必关心它们,也不必诉诸于反射。

允许这些功能报告成功或失败是合理且可取的,因此请使用功能类型func() error

可能的实现:

type Task struct {
    handler func() error
}

func (t *Task) execute() {
    if err := t.handler(); err != nil {
        fmt.Println("Failed to execute task:", err)
    }
}

现在让我们创建示例作业:

func simpleJob() error {
    fmt.Println("simple")
    return nil
}

func complexJob(s string) {
    fmt.Println("complex", s)
}

这是我们在Task s中使用它们的方式:

t := &Task{handler: simpleJob}
t.execute()

t = &Task{handler: func() error {
    complexJob("data")
    return nil
}}
t.execute()

哪个输出(在Go Playground上尝试):

simple
complex data

我们对simpleJob()感到“幸运”:它的签名与处理程序所需的签名匹配,因此我们可以按原样使用它。与签名完全不同的complexJob()不同:它具有一个string参数,并且不会返回error,但是对于匿名函数(闭包),我们仍然可以将其用于{ {1}}。

如果作业需要更多控制或报告功能,则应为其创建一个适当的接口,并且应提交此类接口的值以供执行,而不仅仅是简单的功能。

例如:

Task.handler