dsaob80228 2019-01-10 12:45
浏览 145
已采纳

如何在Go中以字符串形式获取函数的签名

I'm implementing a go module that loads go plugins.

I'm assuming a function with a certain name and a certain signature exists on the main package, and would like to have a nice error message in case it is not found or not matching the expected signature.

Given a variable with a function type, how can one get the underlying signature of that function?

The following only prints the type's name (e.g. main.ModuleInitFunc) and not the full signature.

package main

import "fmt"

type ModuleInitFunc func(someInt int) error

func main() {
    var myFunc ModuleInitFunc = nil

    fmt.Printf("%T", lol)
}
  • 写回答

1条回答 默认 最新

  • douwei7501 2019-01-10 12:58
    关注

    reflect.Type.String() only returns the type name, so if the function value has a named type, you'll only see the type name. Note that this will print the function's signature if the function value is a function literal (has an unnamed type):

    var myFunc ModuleInitFunc
    
    fmt.Printf("%T
    ", myFunc)
    fmt.Printf("%T
    ", func(i int) error { return nil })
    

    Output (try it on the Go Playground):

    main.ModuleInitFunc
    func(int) error
    

    If the type is a named type, we have to construct the signature ourselves, but fortunately the reflect.Type has all the information we need for that.

    Type.In() returns the type of the ith parameter, and similarly Type.Out() returns the type of the ith result type.

    Using those, here's an example implementation that returns the signature of a function value:

    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()
    }
    

    Testing it:

    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(""))
    

    Output (try it on the 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>
    

    Note that it is not possible to also print the names of the parameters and result types, because that is not stored / accessible. For details, see Is unnamed arguments a thing in Go?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了
  • ¥100 H5网页如何调用微信扫一扫功能?
  • ¥15 讲解电路图,付费求解