英文:
Is it possible get information about caller function in Golang?
问题
在Golang中,可以获取关于调用函数的信息吗?例如,如果我有以下代码:
func foo() {
//做一些事情
}
func main() {
foo()
}
如何获取foo
是从main
函数中调用的呢?在其他语言中,我可以轻松实现这个功能(例如在C#中,只需要使用CallerMemberName
类属性)。
英文:
Is it possible get information about caller function in Golang? For example if I have
func foo() {
//Do something
}
func main() {
foo()
}
How can I get that foo
has been called from main
?
I'm able to this in other language (for example in C# I just need to use CallerMemberName
class attribute)
答案1
得分: 120
你可以使用runtime.Caller
来轻松获取关于调用者的信息:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
示例 #1: 打印调用者的文件名和行号:https://play.golang.org/p/cdO4Z4ApHS
package main
import (
"fmt"
"runtime"
)
func foo() {
_, file, no, ok := runtime.Caller(1)
if ok {
fmt.Printf("called from %s#%d\n", file, no)
}
}
func main() {
foo()
}
示例 #2: 使用runtime.FuncForPC
获取更多信息:https://play.golang.org/p/y8mpQq2mAv
package main
import (
"fmt"
"runtime"
)
func foo() {
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
fmt.Printf("called from %s\n", details.Name())
}
}
func main() {
foo()
}
英文:
<!-- language-all: lang-go -->
You can use runtime.Caller
for easily retrieving information about the caller:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
Example #1: Print caller file name and line number: https://play.golang.org/p/cdO4Z4ApHS
package main
import (
"fmt"
"runtime"
)
func foo() {
_, file, no, ok := runtime.Caller(1)
if ok {
fmt.Printf("called from %s#%d\n", file, no)
}
}
func main() {
foo()
}
Example #2: Get more information with runtime.FuncForPC
: https://play.golang.org/p/y8mpQq2mAv
package main
import (
"fmt"
"runtime"
)
func foo() {
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
fmt.Printf("called from %s\n", details.Name())
}
}
func main() {
foo()
}
答案2
得分: 32
扩展我的评论,这里是一些返回当前函数调用者的代码:
import (
"fmt"
"runtime"
)
func getFrame(skipFrames int) runtime.Frame {
// 我们需要索引为 skipFrames+2 的帧,因为我们不想要 runtime.Callers 和 getFrame 自身的帧
targetFrameIndex := skipFrames + 2
// 设置大小为 targetFrameIndex+2,以确保我们有足够的空间来存储比我们需要的多一个调用者
programCounters := make([]uintptr, targetFrameIndex+2)
n := runtime.Callers(0, programCounters)
frame := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(programCounters[:n])
for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
var frameCandidate runtime.Frame
frameCandidate, more = frames.Next()
if frameIndex == targetFrameIndex {
frame = frameCandidate
}
}
}
return frame
}
// MyCaller 返回调用它的函数的调用者 :)
func MyCaller() string {
// 跳过 GetCallerFunctionName 和获取调用者的函数
return getFrame(2).Function
}
// foo 调用 MyCaller
func foo() {
fmt.Println(MyCaller())
}
// bar 是我们想要在输出中看到的 - 它是我们的 "caller"
func bar() {
foo()
}
func main() {
bar()
}
更多示例请参考:https://play.golang.org/p/cv-SpkvexuM
英文:
expanding on my comment, here's some code that returns the current func's caller
import(
"fmt"
"runtime"
)
func getFrame(skipFrames int) runtime.Frame {
// We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
targetFrameIndex := skipFrames + 2
// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
programCounters := make([]uintptr, targetFrameIndex+2)
n := runtime.Callers(0, programCounters)
frame := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(programCounters[:n])
for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
var frameCandidate runtime.Frame
frameCandidate, more = frames.Next()
if frameIndex == targetFrameIndex {
frame = frameCandidate
}
}
}
return frame
}
// MyCaller returns the caller of the function that called it :)
func MyCaller() string {
// Skip GetCallerFunctionName and the function to get the caller of
return getFrame(2).Function
}
// foo calls MyCaller
func foo() {
fmt.Println(MyCaller())
}
// bar is what we want to see in the output - it is our "caller"
func bar() {
foo()
}
func main(){
bar()
}
For more examples: https://play.golang.org/p/cv-SpkvexuM
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论