我是新手,想实现一个可以接收任务的调度程序(即间隔+处理程序)。 我陷入了我应该获得处理程序的部分,因为它是一种静态语言(我无法获得通用函数签名)。 我想出了以下解决方案: 每个“处理程序”功能都将被空接口包装:
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)
}
我的问题是这是处理泛型函数的正确方法,还是我缺少一种惯用的解决方案? 谢谢。
答案 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