如何在Go语言中通过通道发送任意函数?

huangapple go评论110阅读模式
英文:

how to send any function through a channel in golang?

问题

我可以帮你翻译代码部分,以下是翻译好的内容:

我想要实现一个类似下面的执行器:

  1. type task func()
  2. type executor struct {
  3. tasks chan task
  4. }
  5. func (e *executor) Push(t task) {
  6. select {
  7. case e.tasks <- t:
  8. default:
  9. return
  10. }
  11. }
  12. func (e *executor) Run() {
  13. for {
  14. select {
  15. case t := <-e.tasks:
  16. t()
  17. }
  18. }
  19. }
  20. func (e *executor) Init() {
  21. e.tasks = make(chan task, 10)
  22. }

然后,我想要将任何函数包装成task类型,就像这个伪代码所示:

  1. func make_task(f function_addr, args ...interface{}) task {
  2. return func() {
  3. f(args...)
  4. }
  5. }

我该如何实现这个功能?

英文:

I want to implement an executor like below:

  1. type task func()
  2. type executor struct {
  3. tasks chan task
  4. }
  5. func (e *executor) Push(t task) {
  6. select {
  7. case e.tasks &lt;- t:
  8. default:
  9. return
  10. }
  11. }
  12. func (e *executor) Run() {
  13. for {
  14. select {
  15. case t := &lt;-e.tasks:
  16. t()
  17. }
  18. }
  19. }
  20. func (e *executor) Init() {
  21. e.tasks = make(chan task, 10)
  22. }

Then, I want to wrap any function into task type, like this pseudo code:

  1. func make_task(f function_addr, args ...interface{}) task{
  2. return func(){
  3. f(args...)
  4. }
  5. }

How can I achieve this?

答案1

得分: 1

你无法编写一个通用函数来实现你想要的功能,但是你可以使用闭包来实现你需要的功能,例如:

  1. executor.Push(func() {
  2. someFunc(arg1,arg2,...)
  3. })

其中 arg1arg2 等是在代码中的那一点可用的参数。

英文:

You can't write a generic function to do what you want, but you can do what you need using closures like:

  1. executor.Push(func() {
  2. someFunc(arg1,arg2,...)
  3. })

where arg1, arg2, etc. are arguments available at that point in code.

答案2

得分: 0

简单的方法是在make_task的位置使用一个函数字面量:

  1. t := func() { exampleFunction(exampleArg1, exampleArg2) }
  2. e.Push(t)

如果由于某种原因简单的方法不适用于你的应用程序,那么可以使用reflect包来调用任意函数并传递任意参数:

  1. func make_task(f interface{}, args ...interface{}) task {
  2. return func() {
  3. values := make([]reflect.Value, len(args))
  4. for i := range args {
  5. values[i] = reflect.ValueOf(args[i])
  6. }
  7. reflect.ValueOf(f).Call(values)
  8. }
  9. }

示例:

  1. func hello(arg string) {
  2. fmt.Println("Hello", arg)
  3. }
  4. ...
  5. t := make_task(hello, "world")
  6. t() // 输出 Hello world

点击此处查看示例代码。

英文:

The simple approach is to use a function literal in place of make_task:

  1. t := func() { exampleFunction(exampleArg1, exampleArg2) }
  2. e.Push(t)

If the simple approach does not fit into your application for some reason, then use the reflect package to call an arbitrary function with arbitrary arguments:

  1. func make_task(f interface{}, args ...interface{}) task {
  2. return func() {
  3. values := make([]reflect.Value, len(args))
  4. for i := range args {
  5. values[i] = reflect.ValueOf(args[i])
  6. }
  7. reflect.ValueOf(f).Call(values)
  8. }
  9. }

Example:

  1. func hello(arg string) {
  2. fmt.Println(&quot;Hello&quot;, arg)
  3. }
  4. t := make_task(hello, &quot;world&quot;)
  5. t() // prints Hello world

https://go.dev/play/p/5b6VPfV45qo

huangapple
  • 本文由 发表于 2021年11月29日 11:57:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/70149591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定