【问题标题】:Is it possible get information about caller function in Golang?是否可以在 Golang 中获取有关调用者函数的信息?
【发布时间】:2026-01-17 04:45:01
【问题描述】:

是否可以在 Golang 中获取有关调用者函数的信息?例如,如果我有

func foo() {
    //Do something
}
func main() {
    foo() 
}

我怎样才能知道foo 已从main 调用?
我可以用其他语言做到这一点(例如在 C# 中我只需要使用CallerMemberName 类属性)

【问题讨论】:

标签: go


【解决方案1】:

您可以使用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()
}

【讨论】:

  • 这个应该是正确的答案。
  • 是否可以获取调用者函数的函数参数?
  • 我积极使用这种方法,但现在可能应该对其进行现代化改造,因为存在包装错误。
【解决方案2】:

扩展我的评论,这里有一些返回当前函数调用者的代码

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()
}

更多示例:https://play.golang.org/p/cv-SpkvexuM

【讨论】:

  • 我可能很傻,但是你为什么要从runtime.FuncForPC中的fpc中减去1?
  • @Femaref TBH 我不记得了 :) 应该没有理由这样做,但这是从一段工作代码中复制而来的。
  • @Femaref:根据godoc on runtime.Callers,您需要减去,因为它“通常会在调用之后立即返回指令的文件和行号”。该文档还建议不要为此目的使用此函数,而是使用 runtime.Frames。
  • 而不是使用runtime.Callers的结果,应该使用runtime.CallersFrames,如下所示:*.com/a/46289376/5250939和文档中描述:godoc.org/runtime#Callers
  • @BoSunesen 这个答案早于 CallersFrames,请随时提出修改建议。
最近更新 更多