使用反射获取函数的名称

huangapple go评论88阅读模式
英文:

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&#39;s frame
	if len(optFuncLevel) &gt; 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(), &quot;/&quot;, 2)
		if len(farr) &lt; 2 {
			return
		}
		return farr[1]
	}

	return
}

huangapple
  • 本文由 发表于 2012年5月25日 01:51:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/10742749.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定