我正在尝试使用 Go 的反射系统来检索函数的名称,但是在调用其类型的 Name 方法时得到一个空字符串。这是预期的行为吗?
这是我如何解决问题的一个简单示例:
package main
import "fmt"
import "reflect"
func main() {
typ := reflect.TypeOf(main)
name := typ.Name()
fmt.Println("Name of function" + name)
}
我正在尝试使用 Go 的反射系统来检索函数的名称,但是在调用其类型的 Name 方法时得到一个空字符串。这是预期的行为吗?
这是我如何解决问题的一个简单示例:
package main
import "fmt"
import "reflect"
func main() {
typ := reflect.TypeOf(main)
name := typ.Name()
fmt.Println("Name of function" + name)
}
解决方案是使用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"
,只需对其进行标记。
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
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
}
这是一个经过测试的生产就绪实用程序函数,用于返回函数名称。
注 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
}