为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
波斯汪 2023-06-01 14:25:24
我正在实现一个加载 go 插件的 go 模块。我假设主包中存在一个具有特定名称和特定签名的函数,并且希望在找不到它或与预期签名不匹配时收到一条很好的错误消息。给定一个函数类型的变量,如何获得该函数的底层签名?以下仅打印类型的名称(例如main.ModuleInitFunc)而不是完整的签名。package mainimport "fmt"type ModuleInitFunc func(someInt int) errorfunc main() {    var myFunc ModuleInitFunc = nil    fmt.Printf("%T", lol)}
查看完整描述

1 回答

?
回首忆惘然

TA贡献1847条经验 获得超11个赞

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个参数的类型,同理返回第iType.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 ModuleInitFunc


fmt.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) error

func (int) error

func () time.Time

func (string) (*os.File, error)

func (io.Writer, string, int) *log.Logger

<not a function>

请注意,不可能同时打印参数的名称和结果类型,因为它们无法存储/访问。


查看完整回答
反对 回复 2023-06-01
  • 1 回答
  • 0 关注
  • 125 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信