英文:
how do you log function call return values in golang
问题
我想知道在退出一个Go函数时的返回值。Go语言的defer机制很有帮助,但它在注册defer语句时评估参数,而不是在执行时评估。我可以通过使用一个匿名函数来访问返回值来解决这个问题:
func try() (i int) {
defer func() {fmt.Printf("%d", i)}()
i = 10
return i+1
}
func main() {
try()
}
我认为这样可以正常工作,但我希望以一种通用的方式处理这个问题,也许像这样:
func try(in string) (out int) {
enter("%s", in);exit("%d", out)
}
或者,更好的是,使用反射来输出进入/退出时的参数/返回值。我假设运行时性能不是关键 :).
有没有一种好的方法来做到这一点?Shaba Abhiram的Tracey库在很大程度上可以实现这一点,但没有打印返回值。
英文:
I want to know the return values at time of exit from a golang function. The golang defer mechanism is helpful, but it evaluates arguments at the time the defer statement is registered rather than when it is executed. I can work with this using an anonymous function which accesses the return values:
func try() (int i) {
defer func() {fmt.Printf("%d", i)}()
i = 10
return i+1
}
func main() {
try()
}
This would work ok, i think, but I would like to handle this in a generic manner, perhaps something like:
func try(in string) (out int) {
enter("%s", in);exit("%d", out)
}
or, even better, use reflection to output the arguments/return values at time of entry/exit. I'm assuming runtime performance isn't critical :).
Is there a good way to do this? Shaba Abhiram's handy Tracey lib does go a long way towards this but stops short of printing the return values.
答案1
得分: 3
你在评估中是正确的,延迟函数的参数在延迟被排队时进行求值,而不是在执行时进行求值。
你使用匿名函数引用命名返回值的方法是有效的。另一种方法是传递返回值的地址:
func try() (i int) {
defer printReturns(time.Now(), &i)
time.Sleep(10 * time.Millisecond)
i = 10
return i + 1
}
func printReturns(start time.Time, rets ...interface{}) {
fmt.Println(time.Now().Sub(start))
for _, ret := range rets {
fmt.Println(ret)
}
}
这种方法的问题是,你的日志函数现在有一个指针而不是真实类型,并且必须解引用指针才能对其进行任何操作。但如果你使用reflect
,那就不是非常困难。
英文:
You are correct in assesing that the arguments to a deferred function are evaluated at the point the defer is queued, not when it is executed.
Your method of making an anonymous function that refers to named returns is valid. Another approach is to pass in the address of the return values:
func try() (i int) {
defer printReturns(time.Now(), &i)
time.Sleep(10 * time.Millisecond)
i = 10
return i + 1
}
func printReturns(start time.Time, rets ...interface{}) {
fmt.Println(time.Now().Sub(start))
for _,ret := range rets{
fmt.Println(ret)
}
}
The problem with this approach is that your logging function now has a pointer instead of the real type and must unwrap the pointers to do anything with them. But if you are using reflect
, that is not horribly difficult.
答案2
得分: 2
你可以使用godebug来实现最接近的效果,而不需要添加大量的printf
语句。它基本上会为你添加printf
语句。
英文:
The closest thing you will get to do it without adding a lot of printf
's is using godebug, which pretty much adds the printfs
for you.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论