23

我正在尝试使用 Go 的反射系统来检索函数的名称,但是在调用其类型的 Name 方法时得到一个空字符串。这是预期的行为吗?

这是我如何解决问题的一个简单示例:

package main

import "fmt"
import "reflect"

func main() {
    typ := reflect.TypeOf(main)
    name := typ.Name()
    fmt.Println("Name of function" + name)
}
4

4 回答 4

34

解决方案是使用FuncForPc返回一个*Func.

这返回"main.main"

package main

import "fmt"
import "reflect"
import "runtime"


func main() {
    name := runtime.FuncForPC(reflect.ValueOf(main).Pointer()).Name()
    fmt.Println("Name of function : " + name)
}

如果需要"main",只需对其进行标记。

于 2012-05-24T18:04:34.760 回答
32
package main

import "fmt"
import "runtime"

func main() {
    pc, _, _, _ := runtime.Caller(0)
    fmt.Println("Name of function: " + runtime.FuncForPC(pc).Name())
    fmt.Println()

    // or, define a function for it
    fmt.Println("Name of function: " + funcName())
    x()
}

func funcName() string {
    pc, _, _, _ := runtime.Caller(1)
    return runtime.FuncForPC(pc).Name()
}

func x() {
    fmt.Println("Name of function: " + funcName())
    y()
}

func y() {
    fmt.Println("Name of function: " + funcName())
    z()
}
func z() {
    fmt.Println("Name of function: " + funcName())
}

输出:

函数名称:main.main

函数名:main.main
函数名:main.x
函数名:main.y
函数名:main.z

于 2012-05-24T19:08:33.777 回答
3
import runtime

func funcName() string {
    pc, _, _, _ := runtime.Caller(1)
    nameFull := runtime.FuncForPC(pc).Name()    // main.foo
    nameEnd := filepath.Ext(nameFull)           // .foo
    name := strings.TrimPrefix(nameEnd, ".")    // foo
    return name
}
于 2017-01-16T09:00:22.980 回答
0

这是一个经过测试的生产就绪实用程序函数,用于返回函数名称。

注 1:我们正在处理来自 nil 指针的可能性FuncForPC

注 2: optFuncLevel 只是堆栈帧级别的友好名称。这使我们可以灵活地在另一层实用函数中使用它。say 的直接调用main只会传递 1(或者默认情况下什么都不传递),但是如果我在调用FunctionName日志丰富函数,比如PrettyLog()从常规代码调用,我会像FunctionName(2)在 PrettyLog 的调用中那样调用它,所以函数名称返回的是 PrettyLog 调用者的名字,而不是 PrettyLog 本身。

// FunctionName returns the function name of the caller
// optFuncLevel passes the function level to go back up.
// The default is 1, referring to the caller of this function
func FunctionName(optFuncLevel ...int) (funcName string) {
    frameLevel := 1 // default to the caller's frame
    if len(optFuncLevel) > 0 {
        frameLevel = optFuncLevel[0]
    }

    if pc, _, _, ok := runtime.Caller(frameLevel); ok {
        fPtr := runtime.FuncForPC(pc)
        if fPtr == nil {
            return
        }
        // Shorten full function name a bit
        farr := strings.SplitN(fPtr.Name(), "/", 2)
        if len(farr) < 2 {
            return
        }
        return farr[1]
    }

    return
}
于 2021-10-22T16:24:37.283 回答