Go:按名称查找功能

Rob*_*mer 6 reflection casting go type-safety go-reflect

我是新手,输入安全,无法弄清楚如何做以下

package main

func test(){
    print("In Test")
}

func main(){
    a := "test"
    a()
}
Run Code Online (Sandbox Code Playgroud)

小智 13

如果你陈述你想要达到的目标,你可能会得到更好的答案,因为反思通常不是最好的方法.但是如果函数是类型上的方法,则反射将有所帮助(net/rpc就是这样的一个例子).

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())
}
Run Code Online (Sandbox Code Playgroud)

如果你想知道像godoc这样的工具是如何工作的,他们会解析源而不是使用反射.

编辑:游乐场版本


Eva*_*haw 8

没有办法按名称动态查找函数,但我认为值得一提的原因.基本上,原因是编译器和/或链接器可以消除未使用的功能.

考虑一下,如果你能够通过名称获得一个函数,那么每个导入包中的每个函数(递归地)都必须链接到最终的可执行文件中,即使它从未被使用过,以防万一有人想查找它名称.人们已经抱怨大量的Go二进制文件,但这会导致它们更大.

  • 这相当于通过名称动态获取函数. (2认同)

Ste*_*erg 7

无法从字符串中解析函数.但是,您可以为变量分配函数.

a := test
a()
Run Code Online (Sandbox Code Playgroud)

您还可以将函数(假设它们都具有相同的签名)放入映射中:

var func_map :=  map[string]func() {
    "test": test,
}
a := func_map["test"]
a()
Run Code Online (Sandbox Code Playgroud)


OP对第一条评论的回应(太长时间无法发表评论):

  1. 函数不是"文字"."文字"有一个单独的含义.
  2. 其次,Go的运行时反射没有将字符串映射到函数的查找表.即使它确实如此,除非通过其他代码链接,否则函数不会链接到二进制文件中.仅在此方法中调用的代码不会在二进制文件中.
  3. 第三,手动制作映射并不难.它提供编译时类型安全检查以及安全性.
  4. 这不是你应该用任何语言做的事情.它就像eval(),你真的不应该使用它,因为它可能非常危险并导致不可预测的事情发生.

它们并非都具有相同的签名

如果他们没有相同的签名,你打算如何打电话给他们?您可以使用该reflect软件包,但这通常表明您做错了什么.

这不是一种动态语言,有些事情不能在Go中完成.虽然,它们大多是你不应该在大多数语言中做的事情.