英文:
Get name of function using reflection
问题
我正在尝试使用Go的反射系统来获取函数的名称,但是当调用其类型的Name方法时,我得到一个空字符串。这是预期的行为吗?
这是我解决问题的一个简单示例:
package main
import "fmt"
import "reflect"
func main() {
typ := reflect.TypeOf(main)
name := typ.Name()
fmt.Println("函数的名称" + name)
}
英文:
I'm trying to use Go's reflection system to retrieve the name of a function but I get an empty string when calling the Name method on its type. Is this the expected behavior?
This is a simple example of how I approach the problem:
package main
import "fmt"
import "reflect"
func main() {
typ := reflect.TypeOf(main)
name := typ.Name()
fmt.Println("Name of function" + name)
}
答案1
得分: 40
解决方案是使用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)
}
如果你只想要"main"
,只需将其分词化。
英文:
The solution is to use FuncForPc which returns a *Func
.
This returns "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)
}
If you want "main"
, just tokenize it.
答案2
得分: 33
package main
import "fmt"
import "runtime"
func main() {
pc, _, _, _ := runtime.Caller(0)
fmt.Println("函数名: " + runtime.FuncForPC(pc).Name())
fmt.Println()
// 或者,为其定义一个函数
fmt.Println("函数名: " + funcName())
x()
}
func funcName() string {
pc, _, _, _ := runtime.Caller(1)
return runtime.FuncForPC(pc).Name()
}
func x() {
fmt.Println("函数名: " + funcName())
y()
}
func y() {
fmt.Println("函数名: " + funcName())
z()
}
func z() {
fmt.Println("函数名: " + funcName())
}
英文:
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())
}
Output:
> Name of function: main.main
>
> Name of function: main.main
> Name of function: main.x
> Name of function: main.y
> Name of function: main.z
答案3
得分: 4
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
}
英文:
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
}
答案4
得分: 0
这是一个经过测试的生产就绪的实用函数,用于返回函数名。
注意1:我们处理了FuncForPC
可能返回空指针的情况。
注意2:optFuncLevel
只是堆栈帧级别的友好名称。这使我们能够在另一层实用函数中使用它。如果我从main
直接调用,只需传递1(或者什么都不传,因为默认值),但如果我在一个日志增强函数中调用FunctionName
,比如PrettyLog()
,它是从常规代码中调用的,我会在从PrettyLog调用中调用FunctionName(2)
,这样返回的函数名就是调用PrettyLog的调用者的名称,而不是PrettyLog本身。
// FunctionName返回调用者的函数名
// optFuncLevel传递要返回的函数级别
// 默认值为1,表示调用此函数的调用者
func FunctionName(optFuncLevel ...int) (funcName string) {
frameLevel := 1 // 默认为调用者的帧
if len(optFuncLevel) > 0 {
frameLevel = optFuncLevel[0]
}
if pc, _, _, ok := runtime.Caller(frameLevel); ok {
fPtr := runtime.FuncForPC(pc)
if fPtr == nil {
return
}
// 稍微缩短完整的函数名
farr := strings.SplitN(fPtr.Name(), "/", 2)
if len(farr) < 2 {
return
}
return farr[1]
}
return
}
英文:
This is a tested production ready utility function for returning function name.
Note 1: We are handling the possibility of a nil pointer from FuncForPC
Note 2: optFuncLevel is just a friendly name for stack frame level. This gives us the flexibility of using this within another layer of utility functions.
A direct call from say main
would just pass 1 (or nothing since default), but if I am calling FunctionName
in a log enriching function, say PrettyLog()
that is called from regular code, I would call it as FunctionName(2)
in the call from PrettyLog, so the function name returned is the name of the caller of PrettyLog, not PrettyLog itself.
// 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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论