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

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

how to send any function through a channel in golang?

问题

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

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

type task func()

type executor struct {
	tasks chan task
}

func (e *executor) Push(t task) {
	select {
	case e.tasks <- t:
	default:
		return
	}
}

func (e *executor) Run() {
	for {
		select {
		case t := <-e.tasks:
			t()
		}
	}
}

func (e *executor) Init() {
	e.tasks = make(chan task, 10)
}

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

func make_task(f function_addr, args ...interface{}) task {
	return func() {
		f(args...)
	}
}

我该如何实现这个功能?

英文:

I want to implement an executor like below:

type task func()

type executor struct {
	tasks chan task
}

func (e *executor) Push(t task) {
	select {
	case e.tasks &lt;- t:
	default:
		return
	}
}
func (e *executor) Run() {
	for {
		select {
		case t := &lt;-e.tasks:
			t()

		}
	}
}
func (e *executor) Init() {
	e.tasks = make(chan task, 10)
}

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

func make_task(f function_addr, args ...interface{}) task{
	return func(){
    f(args...)
}
}

How can I achieve this?

答案1

得分: 1

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

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

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

英文:

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

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

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

答案2

得分: 0

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

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

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

func make_task(f interface{}, args ...interface{}) task {
    return func() {
        values := make([]reflect.Value, len(args))
        for i := range args {
            values[i] = reflect.ValueOf(args[i])
        }
        reflect.ValueOf(f).Call(values)
    }
}

示例:

func hello(arg string) {
    fmt.Println("Hello", arg)
}

...

t := make_task(hello, "world")
t()  // 输出 Hello world

点击此处查看示例代码。

英文:

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

t := func() { exampleFunction(exampleArg1, exampleArg2) }
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:

func make_task(f interface{}, args ...interface{}) task {
	return func() {
		values := make([]reflect.Value, len(args))
		for i := range args {
			values[i] = reflect.ValueOf(args[i])
		}
		reflect.ValueOf(f).Call(values)
	}
}

Example:

func hello(arg string) {
	fmt.Println(&quot;Hello&quot;, arg)
}

…

t := make_task(hello, &quot;world&quot;)
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:

确定