如何在go中获取函数的签名作为字符串

我正在实现一个加载 go 插件的 go 模块。


我假设主包中存在一个具有特定名称和特定签名的函数,并且希望在找不到它或与预期签名不匹配时收到一条很好的错误消息。


给定一个函数类型的变量,如何获得该函数的底层签名?


以下仅打印类型的名称(例如main.ModuleInitFunc)而不是完整的签名。


package main


import "fmt"


type ModuleInitFunc func(someInt int) error


func main() {

    var myFunc ModuleInitFunc = nil


    fmt.Printf("%T", lol)

}


波斯汪
浏览 88回答 1
1回答

回首忆惘然

reflect.Type.String()仅返回类型名称,因此如果函数值具有命名类型,您只会看到类型名称。请注意,如果函数值是函数文字(具有未命名类型),这将打印函数的签名:var myFunc ModuleInitFunc fmt.Printf("%T\n", myFunc) fmt.Printf("%T\n", func(i int) error { return nil })输出(在Go Playground上尝试):main.ModuleInitFunc func(int) error如果该类型是命名类型,我们必须自己构造签名,但幸运的是,它reflect.Type拥有我们需要的所有信息。Type.In()返回第i个参数的类型,同理返回第i个Type.Out()结果类型的类型。使用这些,这是一个返回函数值签名的示例实现:func signature(f interface{}) string {    t := reflect.TypeOf(f)    if t.Kind() != reflect.Func {        return "<not a function>"    }    buf := strings.Builder{}    buf.WriteString("func (")    for i := 0; i < t.NumIn(); i++ {        if i > 0 {            buf.WriteString(", ")        }        buf.WriteString(t.In(i).String())    }    buf.WriteString(")")    if numOut := t.NumOut(); numOut > 0 {        if numOut > 1 {            buf.WriteString(" (")        } else {            buf.WriteString(" ")        }        for i := 0; i < t.NumOut(); i++ {            if i > 0 {                buf.WriteString(", ")            }            buf.WriteString(t.Out(i).String())        }        if numOut > 1 {            buf.WriteString(")")        }    }    return buf.String()}测试它:var myFunc ModuleInitFuncfmt.Println(signature(func(i int) error { return nil }))fmt.Println(signature(myFunc))fmt.Println(signature(time.Now))fmt.Println(signature(os.Open))fmt.Println(signature(log.New))fmt.Println(signature(""))输出(在Go Playground上尝试):func (int) errorfunc (int) errorfunc () time.Timefunc (string) (*os.File, error)func (io.Writer, string, int) *log.Logger<not a function>请注意,不可能同时打印参数的名称和结果类型,因为它们无法存储/访问。
打开App,查看更多内容
随时随地看视频慕课网APP