【问题标题】:How to get the name of a function in Go?如何在 Go 中获取函数的名称?
【发布时间】:2011-10-26 12:45:42
【问题描述】:

给定一个函数,是否有可能得到它的名字?说:

func foo() {
}

func GetFunctionName(i interface{}) string {
    // ...
}

func main() {
    // Will print "name: foo"
    fmt.Println("name:", GetFunctionName(foo))
}

有人告诉我runtime.FuncForPC 会有所帮助,但我不明白如何使用它。

【问题讨论】:

    标签: go reflection go-reflect


    【解决方案1】:

    我找到了解决办法:

    package main
    
    import (
        "fmt"
        "reflect"
        "runtime"
    )
    
    func foo() {
    }
    
    func GetFunctionName(i interface{}) string {
        return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
    }
    
    func main() {
        // This will print "name: main.foo"
        fmt.Println("name:", GetFunctionName(foo))
    }
    

    【讨论】:

    • 虽然这似乎可行,但此处可能需要注意:.Pointer() 的文档指出“如果 v 的 Kind 是 Func,则返回的指针是底层代码指针,但不一定足以唯一标识单个函数。唯一的保证是当且仅当 v 是 nil func 值时结果为零。"
    • @jochen “不是单个函数”意味着它可能返回误报(即不同函数的指针)?
    • @themihai 我不知道,我引用的这句话是golang.org/pkg/reflect/#Value.Pointer 的所有文档都谈到了这一点。但是这句话似乎表明人们可以为不同的功能获得相同的指针,不是吗?如果是这种情况,GetFunctionName 可能会为不同的函数返回相同的名称?
    • @jochen 我认为这与闭包有关;如果您创建两个具有相同底层函数的闭包,即使它们关闭的值不同,它们也是等价的。
    【解决方案2】:

    不完全是您想要的,因为它记录了文件名和行号,但这是我在 Tideland 通用 Go 库 (http://tideland-cgl.googlecode.com/) 中使用“运行时”包的方法:

    // Debug prints a debug information to the log with file and line.
    func Debug(format string, a ...interface{}) {
        _, file, line, _ := runtime.Caller(1)
        info := fmt.Sprintf(format, a...)
    
        log.Printf("[cgl] debug %s:%d %v", file, line, info)
    

    【讨论】:

    • 这并没有真正的帮助。我不需要获取有关调用堆栈的信息,而是有关给定函数的信息。如果我知道如何在给定函数引用的情况下获取相应的 pc(如果可能的话),我相信这个问题会得到解答。
    【解决方案3】:

    更好的解决方案

    我实际上找到了一个更好的解决方案,在这个函数中,你只需简单地传递一个函数,输出就会简单直接。

    package main
    
    import (
        "reflect"
        "runtime"
        "strings"
    )
    
    func GetFunctionName(temp interface{}) string {
        strs := strings.Split((runtime.FuncForPC(reflect.ValueOf(temp).Pointer()).Name()), ".")
        return strs[len(strs)-1]
    }
    

    这是你如何使用它的一个例子:

    package main
    
    import "fmt"
    
    func main() {
        fmt.Println(GetFunctionName(main))
    }
    

    这是你应该期待的答案:

    main
    

    【讨论】:

      【解决方案4】:

      通过获取前一个调用者函数名

      import (
          "os"
          "runtime"
      )
      
      func currentFunction() string {
          counter, _, _, success := runtime.Caller(1)
      
          if !success {
              println("functionName: runtime.Caller: failed")
              os.Exit(1)
          }
      
          return runtime.FuncForPC(counter).Name()
      }
      

      【讨论】:

        猜你喜欢
        • 2011-01-10
        • 1970-01-01
        • 1970-01-01
        • 2015-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多