-2

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

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

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

4

1 回答 1

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

这就是我们如何在Tasks 中使用它们:

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

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

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

simple
complex data

我们很“幸运” simpleJob():它的签名与我们需要的处理程序相匹配,所以我们可以按原样使用它。不像complexJob()which 有一个完全不同的签名:它有一个string参数并且不返回一个error,但是使用匿名函数(一个闭包)我们仍然可以将它用于Task.handler.

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

例如:

type Job interface{
    Execute() error
    Progress() int
    Result() interface{}
}

type Task struct {
    job Job
}

func (t *Task) execute() {
    if err := t.job.Execute(); err != nil {
        fmt.Println("Failed to execute task:", err)
    }
}
于 2020-01-15T14:54:23.190 回答