问题描述
我正在创建模块并使其相互链接。
测试行为时,我正在调用会调用其他程序包的程序包。
有没有一种简便的方法可以通过将来调用的缩进级别来修改fmt软件包的行为。 这样,父级可以在调用子级包之前设置缩进级别+1。
这样,当每个函数打印输出时,我可以轻松地在stdout中看到级联依赖关系:
inside main
calling package X
____entering package X
____calling package Y
________package Y hello world
____leaving package X
back in main.
exiting
解决方法
fmt
软件包不支持此功能。
但是,您可以借助runtime.Callers()
访问通话深度,这意味着您甚至不必手动保持缩进“级别”。
“概念证明”
访问呼叫深度是这样的(对于0
返回main()
,对于从1
调用的函数返回main()
等):
func callDepth() int {
pc := make([]uintptr,100)
return runtime.Callers(6,pc)
}
并使用它,具有自动压痕打印功能:
var tabs = strings.Repeat("\t",100)
func Println(args ...interface{}) {
fmt.Print(tabs[:callDepth()])
fmt.Println(args...)
}
让我们看看它的作用:
func main() {
Println("In main()")
f1()
Println("In main() again")
}
func f1() {
Println("In f1()")
f2()
Println("In f1() again")
}
func f2() {
Println("In f2()")
}
哪个输出(在Go Playground上尝试):
In main()
In f1()
In f2()
In f1() again
In main() again
注释
我称上述解决方案为“概念验证”,因为它不是解决所有情况的解决方案。您必须决定在启动新的goroutine时要如何处理。当启动新的goroutine时,不会从main()
中调用它们,因此传递给runtime.Callers()
的跳过帧应少1(runtime.Callers(5,pc)
而不是runtime.Callers(6,pc)
)。有关如何检测到此错误的信息,请参见Check if function is being called as goroutine or not。
围绕想要运行的fmt函数编写一些包装,以便它们采用缩进级别的额外参数
package main
import "fmt"
// Println replacement
func Println(level int,args ...interface{}) {
for i := level; i > 0; i-- {
fmt.Print("__")
}
fmt.Println(args...)
}
func main() {
Println(0,"here")
Println(1,"there")
Println(2,"everywhere")
Println(2,"Yes,everywhere")
}