Is it possible get information about caller function in Golang?

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

Is it possible get information about caller function in Golang?

问题

在Golang中,可以获取关于调用函数的信息吗?例如,如果我有以下代码:

  1. func foo() {
  2. //做一些事情
  3. }
  4. func main() {
  5. foo()
  6. }

如何获取foo是从main函数中调用的呢?在其他语言中,我可以轻松实现这个功能(例如在C#中,只需要使用CallerMemberName类属性)。

英文:

Is it possible get information about caller function in Golang? For example if I have

  1. func foo() {
  2. //Do something
  3. }
  4. func main() {
  5. foo()
  6. }

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来轻松获取关于调用者的信息:

  1. func Caller(skip int) (pc uintptr, file string, line int, ok bool)

示例 #1: 打印调用者的文件名和行号:https://play.golang.org/p/cdO4Z4ApHS

  1. package main
  2. import (
  3. "fmt"
  4. "runtime"
  5. )
  6. func foo() {
  7. _, file, no, ok := runtime.Caller(1)
  8. if ok {
  9. fmt.Printf("called from %s#%d\n", file, no)
  10. }
  11. }
  12. func main() {
  13. foo()
  14. }

示例 #2: 使用runtime.FuncForPC获取更多信息:https://play.golang.org/p/y8mpQq2mAv

  1. package main
  2. import (
  3. "fmt"
  4. "runtime"
  5. )
  6. func foo() {
  7. pc, _, _, ok := runtime.Caller(1)
  8. details := runtime.FuncForPC(pc)
  9. if ok && details != nil {
  10. fmt.Printf("called from %s\n", details.Name())
  11. }
  12. }
  13. func main() {
  14. foo()
  15. }
英文:

<!-- language-all: lang-go -->

You can use runtime.Caller for easily retrieving information about the caller:

  1. 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

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;runtime&quot;
  5. )
  6. func foo() {
  7. _, file, no, ok := runtime.Caller(1)
  8. if ok {
  9. fmt.Printf(&quot;called from %s#%d\n&quot;, file, no)
  10. }
  11. }
  12. func main() {
  13. foo()
  14. }

Example #2: Get more information with runtime.FuncForPC: https://play.golang.org/p/y8mpQq2mAv

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;runtime&quot;
  5. )
  6. func foo() {
  7. pc, _, _, ok := runtime.Caller(1)
  8. details := runtime.FuncForPC(pc)
  9. if ok &amp;&amp; details != nil {
  10. fmt.Printf(&quot;called from %s\n&quot;, details.Name())
  11. }
  12. }
  13. func main() {
  14. foo()
  15. }

答案2

得分: 32

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

  1. import (
  2. "fmt"
  3. "runtime"
  4. )
  5. func getFrame(skipFrames int) runtime.Frame {
  6. // 我们需要索引为 skipFrames+2 的帧,因为我们不想要 runtime.Callers 和 getFrame 自身的帧
  7. targetFrameIndex := skipFrames + 2
  8. // 设置大小为 targetFrameIndex+2,以确保我们有足够的空间来存储比我们需要的多一个调用者
  9. programCounters := make([]uintptr, targetFrameIndex+2)
  10. n := runtime.Callers(0, programCounters)
  11. frame := runtime.Frame{Function: "unknown"}
  12. if n > 0 {
  13. frames := runtime.CallersFrames(programCounters[:n])
  14. for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
  15. var frameCandidate runtime.Frame
  16. frameCandidate, more = frames.Next()
  17. if frameIndex == targetFrameIndex {
  18. frame = frameCandidate
  19. }
  20. }
  21. }
  22. return frame
  23. }
  24. // MyCaller 返回调用它的函数的调用者 :)
  25. func MyCaller() string {
  26. // 跳过 GetCallerFunctionName 和获取调用者的函数
  27. return getFrame(2).Function
  28. }
  29. // foo 调用 MyCaller
  30. func foo() {
  31. fmt.Println(MyCaller())
  32. }
  33. // bar 是我们想要在输出中看到的 - 它是我们的 "caller"
  34. func bar() {
  35. foo()
  36. }
  37. func main() {
  38. bar()
  39. }

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

英文:

expanding on my comment, here's some code that returns the current func's caller

  1. import(
  2. &quot;fmt&quot;
  3. &quot;runtime&quot;
  4. )
  5. func getFrame(skipFrames int) runtime.Frame {
  6. // We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
  7. targetFrameIndex := skipFrames + 2
  8. // Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
  9. programCounters := make([]uintptr, targetFrameIndex+2)
  10. n := runtime.Callers(0, programCounters)
  11. frame := runtime.Frame{Function: &quot;unknown&quot;}
  12. if n &gt; 0 {
  13. frames := runtime.CallersFrames(programCounters[:n])
  14. for more, frameIndex := true, 0; more &amp;&amp; frameIndex &lt;= targetFrameIndex; frameIndex++ {
  15. var frameCandidate runtime.Frame
  16. frameCandidate, more = frames.Next()
  17. if frameIndex == targetFrameIndex {
  18. frame = frameCandidate
  19. }
  20. }
  21. }
  22. return frame
  23. }
  24. // MyCaller returns the caller of the function that called it :)
  25. func MyCaller() string {
  26. // Skip GetCallerFunctionName and the function to get the caller of
  27. return getFrame(2).Function
  28. }
  29. // foo calls MyCaller
  30. func foo() {
  31. fmt.Println(MyCaller())
  32. }
  33. // bar is what we want to see in the output - it is our &quot;caller&quot;
  34. func bar() {
  35. foo()
  36. }
  37. func main(){
  38. bar()
  39. }

For more examples: https://play.golang.org/p/cv-SpkvexuM

huangapple
  • 本文由 发表于 2016年2月5日 06:34:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/35212985.html
匿名

发表评论

匿名网友

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

确定