runtime: goroutine stack exceeds 1000000000-byte limit, fatal error: stack overflow on printing a nested struct

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

runtime: goroutine stack exceeds 1000000000-byte limit, fatal error: stack overflow on printing a nested struct

问题

我有一个嵌套的结构体。

  1. type ConfigOne struct {
  2. // 配置文件中的 Daemon 部分。
  3. Daemon daemon
  4. }
  5. type daemon struct {
  6. Loglevel int
  7. Logfile string
  8. }

我在这个类型上有一个 String() string 方法,我试图返回嵌套结构体的元素。

  1. func (c ConfigOne)String() string {
  2. return fmt.Sprintf("%+v\n", c)
  3. }

当我尝试打印它时:

  1. c := &modules.ConfigOne{}
  2. c.Daemon.Loglevel = 1
  3. c.Daemon.Logfile = "/tmp/test.log"
  4. modules.Logger.Infoln(c.String())

我得到了错误:

  1. runtime: goroutine stack exceeds 1000000000-byte limit
  2. fatal error: stack overflow
  3. runtime stack:
  4. runtime.throw(0x6ea3b7, 0xe)
  5. ...

在查看错误后,我发现重复的行类似于下面的行:

  1. modules/structs.go:31 +0x77 fp=0xc440100398 sp=0xc440100328
  2. go-consume/modules.(*ConfigOne).String(0xc42abcb4e0, 0x70bc08, 0xc42abd6300)
  3. <autogenerated>:1 +0x64 fp=0xc4401003d8 sp=0xc440100398
  4. fmt.(*pp).handleMethods(0xc42abd6300, 0xc400000076, 0x410301)

最后,在崩溃之前:

  1. modules/structs.go:31 +0xc0 fp=0xc440103d18 sp=0xc440103ca8
  2. ...additional frames elided...
  3. goroutine 17 [syscall, locked to thread]:
  4. runtime.goexit()

我相信这是由于进入了某种无限递归引起的。

我试图找出原因,并找到了这里,我相信这是相同的问题。然而,我无法理解该线程中的解释。

如果我尝试打印单个嵌套结构体:

  1. func (c ConfigOne)String() string {
  2. //return fmt.Sprintf("%+v\n", c.Daemon.Loglevel)
  3. return fmt.Sprintf("%+v\n", c.Daemon)
  4. }

它可以正常工作,并且日志显示字段为:

  1. 2017/03/05 01:28:25 go-consume.go:38: INFO: {Loglevel:1 Logfile:/tmp/test.log}

有人可以解释一下前面的 String() 方法如何导致无限递归和堆栈溢出,以及如何最好地解决这个问题吗?

英文:

I have a nested struct.

  1. type ConfigOne struct {
  2. // Daemon section from config file.
  3. Daemon daemon
  4. }
  5. type daemon struct {
  6. Loglevel int
  7. Logfile string
  8. }

And I have a String() string method on that type, which I am trying to return the nested struct elements as

  1. func (c ConfigOne)String() string{
  2. return fmt.Sprintf(&quot;%+v\n&quot;, c)
  3. }

When I am trying to print it as

  1. c := &amp;modules.ConfigOne{}
  2. c.Daemon.Loglevel = 1
  3. c.Daemon.Logfile = &quot;/tmp/test.log&quot;
  4. 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

  1. func (c ConfigOne)String() string{
  2. //return fmt.Sprintf(&quot;%+v\n&quot;, c.Daemon.Loglevel)
  3. return fmt.Sprintf(&quot;%+v\n&quot;, c.Daemon)
  4. }

it is working fine, and log shows the fields as

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

huangapple
  • 本文由 发表于 2017年3月5日 04:18:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/42600920.html
匿名

发表评论

匿名网友

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

确定