英文:
Go: lookup function by name
问题
我对类型安全还不熟悉,无法弄清楚如何执行以下操作:
package main
func test(){
print("在测试中")
}
func main(){
a := "测试"
a()
}
英文:
I am new to type safe, and can't figure out how to do following
package main
func test(){
print("In Test")
}
func main(){
a := "test"
a()
}
答案1
得分: 14
如果您说明您想要实现什么,您可能会得到更好的答案,因为反射通常不是最好的方法。但是,如果这些函数是类型的方法(net/rpc是一个示例),则reflect会有所帮助。
package main
import (
"fmt"
"reflect"
)
type T struct {}
func (T) Add(x, y int) int {
return x + y
}
func main() {
t := reflect.ValueOf(T{})
m := t.MethodByName("Add")
args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
fmt.Println(m.Call(args)[0].Int())
}
如果您想知道像godoc这样的工具是如何工作的,它们会解析源代码而不是使用反射。
英文:
You might get better answers if you state what you're trying to achieve, as reflection is usually not the best way. But reflect will help if the functions are methods on a type (net/rpc is an example of this).
package main
import (
"fmt"
"reflect"
)
type T struct {}
func (T) Add(x, y int) int {
return x + y
}
func main() {
t := reflect.ValueOf(T{})
m := t.MethodByName("Add")
args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
fmt.Println(m.Call(args)[0].Int())
}
If you were wondering how tools like godoc work, they parse the source rather than use reflection.
Edit: Playground version
答案2
得分: 8
一个函数无法从字符串中解析。但是,你可以将一个函数赋值给一个变量。
a := test
a()
你也可以将函数(假设它们都有相同的签名)放入一个映射中:
var func_map := map[string]func() {
"test": test,
}
a := func_map["test"]
a()
对于OP的第一个评论的回应(太长了,无法再发表评论):
- 函数不是“字面量”。“字面量”有一个单独的含义。
- 其次,Go的运行时反射没有一个将字符串映射到函数的查找表。即使有,除非被其他代码链接调用,否则函数不会链接到二进制文件中。只在此方法中调用的代码不会出现在二进制文件中。
- 第三,手动创建映射并不难。它提供了编译时类型安全检查以及安全性。
- 这不是你应该在任何语言中做的事情。这就像eval(),你真的不应该使用它,因为它可能非常危险,导致不可预测的事情发生。
它们并不都有相同的签名
如果它们没有相同的签名,你打算如何调用它们?你可以使用reflect
包,但通常这表明你正在做一些错误的事情。
这不是一种动态语言,有些事情在Go中无法完成。尽管如此,它们大多是你在大多数语言中都不应该做的事情。
英文:
A function can not be resolved from a string. However, you can assign a function to a variable.
a := test
a()
You can also put functions (assuming they all have the same signature) into a map:
var func_map := map[string]func() {
"test": test,
}
a := func_map["test"]
a()
<br>
Response to first comment by OP (too long to make another comment):
- A function is not a "literal". "Literal" has a separate meaning.
- Second, Go's runtime reflection does not have a lookup table mapping strings to functions. Even if it did, functions are not linked into the binary unless linked to by other code. Code only called in this method would not be in the binary.
- Third, making a mapping manually is not that hard. It provides compile time type safety checks as well as security.
- This is not something you should be doing in any language. It is like eval(), you really should not use it because it can be incredibly dangerous and cause unpredictable things to happen.
They don't all have the same signature
If they don't all have the same signature, how do you plan to call them? You could use the reflect
package, but that is normally an indication that you are doing something wrong.
This is not a dynamic language and some things can not be done in Go. Although, they are mostly things you should not do in most languages anyways.
答案3
得分: 8
没有办法通过名称动态查找函数,但我认为值得提及为什么。基本上,原因是为了让编译器和/或链接器可以消除未使用的函数。
考虑一下,如果你能够通过名称获取一个函数,那么每个导入包中的每个函数(递归地)都必须链接到最终的可执行文件中,即使它从未被使用过,只是为了防止有人想要通过名称查找它。人们已经抱怨Go二进制文件的大小,但这将导致它们变得更大。
英文:
There's no way to dynamically look up a function by name, but I think it's worth mentioning why. Basically, the reason is so that the compiler and/or linker can eliminate unused functions.
Consider that if you were able to get a function by name, then every function in every imported package (recursively) would have to be linked into the final executable, even if it was never used, just in case someone wanted to look it up by name. People already complain about the large size of Go binaries, but this would cause them to be much larger still.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论