Golang中如何获取函数名称
Golang中如何获取函数名称 我有一个函数,在该函数中调用了另一个函数,我想在内部函数中获取外部函数的名称:
func MyFunc() {
CallFunc()
}
func CallFunc() {
// 我想打印出 MyFunc
}
简单的解决方案是将函数名作为参数传递。但这需要手动操作:
CallFunc("MyFunc")
但我认为应该存在某种无需手动传递函数名的方法。有办法实现吗?
我也是来建议这个解决方案的。它可以在(不那么)野外找到:appliedgo.net/what 是一个临时的故障排除工具,它通过这种方式获取当前函数名。
(抱歉自我推销一下。^-^)
如果你想要一个对熟悉Go堆栈跟踪的人来说格式良好的调用栈,Dean的建议非常棒。如果你只想获取调用函数的名称,可以这样做:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("from main:", CallerName(0))
func2()
}
func func2() {
fmt.Println("from func2:", CallerName(0))
fmt.Println(CallerName(0), "called by", CallerName(1))
}
func CallerName(skip int) string {
pc, _, _, ok := runtime.Caller(skip + 1)
if !ok {
return ""
}
f := runtime.FuncForPC(pc)
if f == nil {
return ""
}
return f.Name()
}
请注意,这将包含“完全限定”的函数名。main包中的函数名是main.<函数名>,但非main包中的函数名将包含完整的包路径(例如(*github.com/account/project/package.Type).Func)。
或许可以使用类似 runtime.Stack 的方法?
func CallFunc() {
stack := make([]byte, 512)
runtime.Stack(stack, false)
fmt.Println("Stack is:")
fmt.Println(string(stack))
}
在 Go Playground 中运行 会打印出:
Stack is:
goroutine 1 [running]:
main.CallFunc()
/tmp/sandbox549134487/prog.go:20 +0x45
main.MyFunc(...)
/tmp/sandbox549134487/prog.go:15
main.main()
/tmp/sandbox549134487/prog.go:11 +0x18
你可以在这里查看更多信息:
runtime 包 - runtime - Go Packages
runtime 包包含与 Go 运行时系统交互的操作,例如控制 goroutine 的函数。
反射可能也会让你感兴趣:
reflect 包 - reflect - Go Packages
reflect 包实现了运行时反射,允许程序操作任意类型的对象。
不过,听起来你想要的似乎是基于 CallFunc 被调用的位置来提供不同的功能。这听起来确实像是通过参数来实现会更合理。
在Go中可以通过runtime.Caller获取调用栈信息,进而获取函数名称。以下是实现方法:
package main
import (
"fmt"
"runtime"
"strings"
)
func MyFunc() {
CallFunc()
}
func CallFunc() {
// 获取调用者的函数名称
pc, _, _, ok := runtime.Caller(1)
if !ok {
fmt.Println("无法获取调用者信息")
return
}
fn := runtime.FuncForPC(pc)
if fn == nil {
fmt.Println("无法获取函数信息")
return
}
// 获取完整的函数名(包含包路径)
fullName := fn.Name()
// 提取最后的函数名部分
parts := strings.Split(fullName, ".")
funcName := parts[len(parts)-1]
fmt.Printf("调用者函数名: %s\n", funcName) // 输出: MyFunc
}
func main() {
MyFunc()
}
如果需要更通用的工具函数:
func GetCallerFuncName(skip int) string {
pc, _, _, ok := runtime.Caller(skip + 1)
if !ok {
return ""
}
fn := runtime.FuncForPC(pc)
if fn == nil {
return ""
}
fullName := fn.Name()
parts := strings.Split(fullName, ".")
return parts[len(parts)-1]
}
func CallFunc() {
callerName := GetCallerFuncName(1) // 1表示跳过CallFunc本身
fmt.Printf("调用者函数名: %s\n", callerName)
}
对于嵌套调用的情况:
func OuterFunc() {
MiddleFunc()
}
func MiddleFunc() {
CallFunc()
}
func CallFunc() {
// 获取不同层级的调用者
for i := 1; i <= 3; i++ {
pc, _, _, ok := runtime.Caller(i)
if !ok {
break
}
fn := runtime.FuncForPC(pc)
if fn != nil {
fullName := fn.Name()
parts := strings.Split(fullName, ".")
fmt.Printf("层级 %d: %s\n", i, parts[len(parts)-1])
}
}
}
// 输出:
// 层级 1: CallFunc
// 层级 2: MiddleFunc
// 层级 3: OuterFunc
注意:runtime.Caller的参数表示要跳过的调用栈帧数。传递1表示跳过CallFunc本身,获取其调用者。

