struct String()实现导致堆栈溢出Sprintf"+"标志

Mer*_*erl 1 go

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

我有一个结构,我想实现一个String()漂亮的打印方法.我喜欢这里给出的答案,但我不喜欢键入,所以我试图修改它以使用"%+v"结构的格式标志返回一个字符串.来自fmt doc:

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

如果我简单地调用它,这可以正常工作fmt.Printf("%+v", color),但如果我尝试将+标志放在String()实现中,我会得到堆栈溢出(我第一次在stackoverflow.com上询问"堆栈溢出"问题;))

我确定我不理解这里的指针引用,或者有一些递归.我怀疑这个菜鸟找到了我的第一个Golang虫子,所以有人可以解释一下吗?

请参阅此处的播放演示https://play.golang.org/p/13_qI8Iwwa

小智 6

请参阅包fmt文档:

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

  1. 如果操作数实现方法String() string,则将调用该方法将对象转换为字符串,然后根据动词的需要对其进行格式化(如果有).

避免在诸如此类的情况下递归

type X string 
func (x X) String() string { return Sprintf("<%s>", x) }
Run Code Online (Sandbox Code Playgroud)

在重复之前转换值:

func (x X) String() string { return Sprintf("<%s>", string(x)) }
Run Code Online (Sandbox Code Playgroud)

无限递归也可以由自引用数据结构触发,例如,如果该类型具有String方法,则将自身包含为元素.然而,这种病症是罕见的,并且包装不能防止它们.


内:

func (c Color) String() string {
    // THIS CAUSES STACK OVERFLOW
    return fmt.Sprint(c)
}
Run Code Online (Sandbox Code Playgroud)

打电话给

fmt.Sprint(c)
Run Code Online (Sandbox Code Playgroud)

或者fmt.Println(c) 它调用func (c Color) String() string再次递归导致溢出:尝试在旅途游乐场


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

  • 谢谢@amd。您最初的回答指出了明显的递归...但是使用新字符串 (`string(x)`) 会丢失结构引用,因此仍然无法使用“+”标志...但是,您的解决方案中在 String() 方法中使用“#”标志的操场使用 Go 的“语法表示”,给我标签,并避免递归。谢谢! (2认同)