将字符串值转换为函数调用。

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

Convert string value to function call

问题

我想根据一个字符串来指定一个函数。我从一个映射中获取字符串,在下面的示例中,它们是function中的值,而在映射中进行迭代。例如,当字符串值function等于"networkInfo"时,我想将该值作为真实函数的名称来处理。很难解释,但我想你们会知道我的意思。

我的目标是去掉switch语句,并直接调用c.AddFunc(spec, func() { networkInfo() }),其中networkInfo是从字符串function中提取的函数名。我知道这是可能的,但我不知道怎么做 :(. 需要帮助!

// ScheduleCronjobs starts the scheduler
func ScheduleCronjobs() {

tasks := props.P.GetStringMapString("tasks")
log.Infof("number of tasks: %d", len(tasks))

if len(tasks) != 0 {
	c := cron.New()

	// for each task, initialize
	for function, spec := range tasks {
		switch function {
		case "networkInfo":
			c.AddFunc(spec, func() { networkInfo() })
		case "bla":
			c.AddFunc(spec, func() { bla() })
		default:
			log.Errorf("unknown task: %q", function)
		}
	}
	c.Start()
}

// after initialization, send out confirmation message
slack.SendMessage("tasks initialized", props.P.GetString("channel"))
}
英文:

I want to specify a function based on a string. I'm getting strings out of a map, in the example below they are the values in function while interating ove the map. Now for example, when the string value function == "networkInfo", I would like to "treat" that value as a real functions' name. It's hard to explain, but I think you guys will know what I mean.

My goal is to remove the switch statement and directly call c.AddFunc(spec, func() { networkInfo() }) where networkInfo is the function name, extracted from string function. I know this is possible, but I don't know how :(. Help is appreciated!

// ScheduleCronjobs starts the scheduler
func ScheduleCronjobs() {

tasks := props.P.GetStringMapString("tasks")
log.Infof("number of tasks: %d", len(tasks))

if len(tasks) != 0 {
	c := cron.New()

	// for each task, initialize
	for function, spec := range tasks {
		switch function {
		case "networkInfo":
			c.AddFunc(spec, func() { networkInfo() })
		case "bla":
			c.AddFunc(spec, func() { bla() })
		default:
			log.Errorf("unknown task: %q", function)
		}
	}
	c.Start()
}

// after initialization, send out confirmation message
slack.SendMessage("tasks initialized", props.P.GetString("channel"))
}

答案1

得分: 3

为什么不这样做:

taskDefs := map[string]func(){
  "networkInfo": networkInfo,
  "bla": bla,
}

for function, spec := range tasks {
  if fn, ok := taskDefs[function]; ok {
    c.AddFunc(spec, func() { fn() }) // 不确定是否需要封闭的函数
  } else {
    log.Errorf("unknown task: %q", function)
  }
}

如果你需要函数的签名有所不同,那么你实际上需要使用反射,但如果函数的类型都相同,那么使用这种映射的方法可能是一个更简单的解决方案,而且没有反射的开销。

我发现在一个包中按名称查找函数的唯一方法是通过解析源文件。这个仓库是一个将函数找到并存储在以名称为键的映射中的示例。

Go链接器会静默丢弃未被引用的函数,所以如果你通过反射是唯一引用函数的方式,那么它将会失效。这就是为什么我建议使用映射方法更好,它可以让链接器知道函数正在被使用。

英文:

Why not something like:

taskDefs := map[string]func(){
  "networkInfo": networkInfo,
  "bla": bla,
}

for function, spec := range tasks {
  if fn, ok := taskDefs[function]; ok {
    c.AddFunc(spec, func() { fn() }) // not sure if you need the enclosing func
  } else {
    log.Errorf("unknown task: %q", function)
  }
}

If you do need varying signatures of your funcs then you'd actually need reflection, but if the types of the funcs are all the same, then using this map approach might be a simpler solution, without the overhead of reflection.

The only way I've found to find functions by name in a package is by actually parsing the source files. This repo is an example of finding funcs and storing them in a map with the name as the key.

The Go linker will silently drop unreferenced funcs, so if the only way you're referencing the func is through reflection it would break. That is why the map approach I suggest is superior; it let's the linker know the func is being used.

huangapple
  • 本文由 发表于 2016年3月27日 03:05:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/36239614.html
匿名

发表评论

匿名网友

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

确定