如何在Go中获取函数的名称?

mor*_*aes 87 reflection go go-reflect

鉴于一个功能,是否有可能得到它的名字?说:

func foo() {
}

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

func main() {
    // Will print "name: foo"
    fmt.Println("name:", GetFunctionName(foo))
}
Run Code Online (Sandbox Code Playgroud)

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

mor*_*aes 152

很抱歉回答我自己的问题,但我找到了一个解决方案:

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

  • 虽然这似乎有效,但这里可能需要一些注意:.Pointer() 的文档指出“如果 v 的 Kind 是 Func,则返回的指针是底层代码指针,但不一定足以唯一地标识单个函数。唯一的保证结果为零当且仅当 v 是一个 nil func 值。” (4认同)
  • @jochen我认为这与闭包有关; 如果你创建了两个具有相同底层函数的闭包,即使它们关闭的值不同,它们也是等价的. (2认同)

the*_*mue 7

不完全是你想要的,因为它记录了文件名和行号,但这是我在Tideland Common Go Library(http://tideland-cgl.googlecode.com/)中使用"runtime"包的方式:

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

  • 那真的没有帮助。我不需要获取有关调用堆栈的信息,而是获取有关给定函数的信息。我相信如果我知道如何在给定函数引用的情况下获得相应的 pc(如果可能的话),这个问题就会得到解答。 (2认同)

Alb*_*lla 5

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

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