首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >打印Go调用树

打印Go调用树
EN

Stack Overflow用户
提问于 2021-04-24 22:13:44
回答 1查看 422关注 0票数 0

给出这样的文件:

代码语言:javascript
复制
package main

func A() {}

func B() {
   A()
}

func C() {
   A()
}

func D() {
   B()
}

func E() {
   B()
}

func F() {
   C()
}

func G() {
   C()
}

func main() {
   D()
   E()
   F()
   G()
}

我想打印程序的调用树,如下所示:

代码语言:javascript
复制
main
   D
      B
         A
   E
      B
         A
   F
      C
         A
   G
      C
         A

我找到了callgraph程序1,但它没有创建树:

代码语言:javascript
复制
PS C:\prog> callgraph .
prog.A  --static-4:5--> prog.C
prog.A  --static-5:5--> prog.D
prog.main       --static-19:5-->        prog.A
prog.B  --static-9:5--> prog.E
prog.B  --static-10:5-->        prog.F
prog.main       --static-20:5-->        prog.B

有什么方法可以这样做吗?

  1. https://github.com/golang/tools/blob/master/cmd/callgraph
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-05 20:01:31

因此,我确实找到了一个包,它似乎处理了从命令行1上的图表中打印树的问题。然而,我考虑了更多,而打印的树可能不是解决我的问题的最佳方法。我想要做的是,从我的函数中返回一个错误。然而,要做到这一点,我需要将错误一直传播到main。由于这可能是几个层,所以我认为最好从main开始,然后以我的方式实现所需的函数。这样,如果需要的话,我可以分阶段工作。问题是,如何获得这些函数的有序列表?我用tsort 2找到了一个解决方案

代码语言:javascript
复制
PS C:\> callgraph -format digraph . | coreutils tsort
"init/test.main"
"init/test.D"
"init/test.E"
"init/test.F"
"init/test.G"
"init/test.B"
"init/test.C"
"init/test.A"

但我可能不总是想要整个呼叫图。接下来,我考虑添加一个panic

代码语言:javascript
复制
func A() {
   panic(1)
}

但这并不能为您提供所有分支,只有目标函数的第一条路径:

代码语言:javascript
复制
main.A(...)
        C:/test.go:4
main.B(...)
        C:/test.go:8
main.D(...)
        C:/test.go:16
main.main()
        C:/test.go:32 +0x45

最后,我编写了自己的排序函数,该函数以任意目的地作为输入,并按照从main到目标函数的顺序打印所有路径:

代码语言:javascript
复制
package main

func tsort(graph map[string][]string, end string) []string {
   var (
      b = make(map[string]bool)
      l []string
      s = []string{end}
   )
   for len(s) > 0 {
      n := s[len(s) - 1]
      b[n] = true
      for _, m := range graph[n] {
         if ! b[m] {
            s = append(s, m)
         }
      }
      if s[len(s) - 1] == n {
         s = s[:len(s) - 1]
         l = append(l, n)
      }
   }
   return l
}

示例:

代码语言:javascript
复制
package main

import (
   "bytes"
   "fmt"
   "os/exec"
)

func main() {
   b := new(bytes.Buffer)
   c := exec.Command("callgraph", "-format", "digraph", ".")
   c.Stdout = b
   c.Run()
   m := make(map[string][]string)
   for {
      var parent, child string
      _, e := fmt.Fscanln(b, &parent, &child)
      if e != nil { break }
      m[child] = append(m[child], parent)
   }
   for n, s := range tsort(m, `"init/test.A"`) {
      fmt.Print(n+1, ". ", s, "\n")
   }
}

结果:

代码语言:javascript
复制
1. "init/test.main"
2. "init/test.G"
3. "init/test.F"
4. "init/test.C"
5. "init/test.D"
6. "init/test.E"
7. "init/test.B"
8. "init/test.A"

  1. https://github.com/soniakeys/graph/blob/master/treevis/treevis.go
  2. https://github.com/uutils/coreutils
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67247919

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档