英文:
runtime: goroutine stack exceeds 1000000000-byte limit, fatal error: stack overflow on printing a nested struct
问题
我有一个嵌套的结构体。
type ConfigOne struct {
// 配置文件中的 Daemon 部分。
Daemon daemon
}
type daemon struct {
Loglevel int
Logfile string
}
我在这个类型上有一个 String() string
方法,我试图返回嵌套结构体的元素。
func (c ConfigOne)String() string {
return fmt.Sprintf("%+v\n", c)
}
当我尝试打印它时:
c := &modules.ConfigOne{}
c.Daemon.Loglevel = 1
c.Daemon.Logfile = "/tmp/test.log"
modules.Logger.Infoln(c.String())
我得到了错误:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x6ea3b7, 0xe)
...
在查看错误后,我发现重复的行类似于下面的行:
modules/structs.go:31 +0x77 fp=0xc440100398 sp=0xc440100328
go-consume/modules.(*ConfigOne).String(0xc42abcb4e0, 0x70bc08, 0xc42abd6300)
<autogenerated>:1 +0x64 fp=0xc4401003d8 sp=0xc440100398
fmt.(*pp).handleMethods(0xc42abd6300, 0xc400000076, 0x410301)
最后,在崩溃之前:
modules/structs.go:31 +0xc0 fp=0xc440103d18 sp=0xc440103ca8
...additional frames elided...
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
我相信这是由于进入了某种无限递归引起的。
我试图找出原因,并找到了这里,我相信这是相同的问题。然而,我无法理解该线程中的解释。
如果我尝试打印单个嵌套结构体:
func (c ConfigOne)String() string {
//return fmt.Sprintf("%+v\n", c.Daemon.Loglevel)
return fmt.Sprintf("%+v\n", c.Daemon)
}
它可以正常工作,并且日志显示字段为:
2017/03/05 01:28:25 go-consume.go:38: INFO: {Loglevel:1 Logfile:/tmp/test.log}
有人可以解释一下前面的 String()
方法如何导致无限递归和堆栈溢出,以及如何最好地解决这个问题吗?
英文:
I have a nested struct.
type ConfigOne struct {
// Daemon section from config file.
Daemon daemon
}
type daemon struct {
Loglevel int
Logfile string
}
And I have a String() string
method on that type, which I am trying to return the nested struct elements as
func (c ConfigOne)String() string{
return fmt.Sprintf("%+v\n", c)
}
When I am trying to print it as
c := &modules.ConfigOne{}
c.Daemon.Loglevel = 1
c.Daemon.Logfile = "/tmp/test.log"
modules.Logger.Infoln(c.String())
I am getting the error
>runtime: goroutine stack exceeds 1000000000-byte limit
>fatal error: stack overflow
>runtime stack:
>runtime.throw(0x6ea3b7, 0xe)
>...
After going through the error, I could see repeated lines similar to the below one
>modules/structs.go:31 +0x77 fp=0xc440100398 sp=0xc440100328
>go-consume/modules.(*ConfigOne).String(0xc42abcb4e0, 0x70bc08, 0xc42abd6300)
><autogenerated>:1 +0x64 fp=0xc4401003d8 sp=0xc440100398
>fmt.(*pp).handleMethods(0xc42abd6300, 0xc400000076, 0x410301)
and finally, before dying,
>modules/structs.go:31 +0xc0 fp=0xc440103d18 sp=0xc440103ca8
>...additional frames elided...
>goroutine 17 [syscall, locked to thread]:
>runtime.goexit()
which I believe is caused by going into some infinite recursion.
I tried my luck to find the cause and reached here, which I believe is the same issue. However I couldn't understand the explanation in that thread.
If I try to print the individual nested struct as
func (c ConfigOne)String() string{
//return fmt.Sprintf("%+v\n", c.Daemon.Loglevel)
return fmt.Sprintf("%+v\n", c.Daemon)
}
it is working fine, and log shows the fields as
2017/03/05 01:28:25 go-consume.go:38: INFO: {Loglevel:1 Logfile:/tmp/test.log}
Can someone kindly explain how the former String()
method is resulting in an infinite recursion and a stackoverflow, and what is the best way to overcome this?
答案1
得分: 19
%v
和 %+v
格式会使用 String()
方法返回的值,如果该类型实现了该方法。因此,在 String()
方法中对该类型使用 %+v
会导致无限递归。所以,你需要自己构建字符串来展示结构体的内容,以你认为合适的方式。
英文:
The %v
and %+v
formats use the value of String()
if the type implements it. Therefore, using %+v
on a type within the String()
function for that type causes infinite recursion. Instead of using %+v
in the String()
function, you'll have to construct your own string, showing the contents of the structure in whatever way you see fit.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论