2016-09-27 37 views
1

Golang noob问题:为什么我不是使用"%+v"标志为String()实现方法中的结构?struct String()实现导致堆栈溢出与Sprintf“+”标志

我有一个结构,我想实现漂亮打印的String()方法。我喜欢给出的答案here,但我不喜欢输入,所以我试图修改它以返回一个字符串,其格式标记为"%+v"。从fmt DOC:

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

这工作得很好,如果我简单地叫它fmt.Printf("%+v", color),但如果我尝试把+国旗在String()执行,我得到一个堆栈溢出(我第一次有机会问一个“堆栈溢出”的问题上stackoverflow.com;))

我敢肯定,我”没有理解这里的指针引用,或者有s递归。我怀疑这个noob找到了我的第一个Golang错误,那么有人能解释一下吗?

看到去这里https://play.golang.org/p/13_qI8Iwwa

回答

6

发挥示范见Package fmt Docs:在使用动词%T%p,特殊格式 考虑适用于实现某些接口的操作数印刷

除外。 在应用的顺序:

  • 如果操作数实现方法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

    +1

    Thanks @amd。你最初的答案指出了明显的递归......但是使用新字符串('string(x)')失去了结构引用,所以仍然没有办法使用“+”标志......但是,你的解决方案在你的操场使用String()方法中的“#”标志使用Go的“语法表示”,为我提供了标签,并避免了递归。谢谢! – Merl