【问题标题】:struct String() implemention causes stack overflow with Sprintf "+" flagstruct String() 实现导致堆栈溢出并带有 Sprintf“+”标志
【发布时间】:2017-02-05 11:53:29
【问题描述】:

Golang 菜鸟问题:为什么我不能在 String() 实现方法中对结构体使用 "%+v" 标志?

我有一个结构,我想在其中实现一个 String() 方法以进行漂亮的打印。我喜欢here 给出的答案,但我不喜欢打字,所以我试图修改它以使用结构的"%+v" 格式标志返回一个字符串。来自fmt 文档:

%v 打印结构时默认格式的值,加号标志 (%+v) 添加字段名

如果我简单地用fmt.Printf("%+v", color) 调用它,这很好用,但是如果我尝试将+ 标志放在String() 实现中,我会遇到堆栈溢出(我第一次有机会询问“堆栈溢出” stackoverflow.com 上的问题 ;) )

我确定我不理解这里的指针引用,或者有一些递归。我怀疑这个菜鸟发现了我的第一个 Golang 错误,有人可以解释一下吗?

看这里去玩演示https://play.golang.org/p/13_qI8Iwwa

【问题讨论】:

    标签: go


    【解决方案1】:

    您可以通过将类型Color 重新定义为新的本地类型(例如type _Color Color)然后将Sprintf 应用于转换后的值_Color(color) 来绕过无限递归,因为它不能递归调用您的@987654326 @函数。

    func (color Color) String() string {
        type _Color Color
        return fmt.Sprintf("%+v", _Color(color))
    }
    

    注意:不要使用类型别名(例如type _Color = Color),因为这不会引入新类型,而只会为旧类型引入新名称,而您又回到了无限递归问题。

    编辑:我相应地更新了您的示例,因此您可以检查它是否有效:https://go.dev/play/p/Cb1jQTcajc4

    【讨论】:

      【解决方案2】:

      Package fmt Docs:

      使用动词%T%p 打印时除外,特殊格式 注意事项适用于实现某些接口的操作数。 按申请顺序:

      1. 如果操作数实现方法String() string,将调用该方法将对象转换为字符串,然后将 按照动词要求的格式(如果有)。

      为了避免在

      等情况下出现递归
      type X string 
      func (x X) String() string { return Sprintf("<%s>", x) }
      

      在循环之前转换值:

      func (x X) String() string { return Sprintf("<%s>", string(x)) }
      

      自引用数据也可以触发无限递归 结构,例如包含自身作为元素的切片,如果 该类型有一个 String 方法。然而,这样的病症是罕见的,并且 包装不能防止它们。


      内部:

      func (c Color) String() string {
          // THIS CAUSES STACK OVERFLOW
          return fmt.Sprint(c)
      }
      

      来电

      fmt.Sprint(c)
      

      fmt.Println(c)再次递归调用func (c Color) String() string导致溢出:在The Go Playground上试试


      这也很好用:https://play.golang.org/p/NYLtrxUeiA

      【讨论】:

      • 谢谢@amd。您最初的回答指出了明显的递归...但是使用新字符串 (string(x)) 会丢失结构引用,因此仍然无法使用“+”标志...但是,您在操场上使用的解决方案String() 方法中的“#”标志使用 Go 的“语法表示”,给我标签,并避免递归。谢谢!
      猜你喜欢
      • 2018-11-27
      • 1970-01-01
      • 2015-05-21
      • 2014-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多