为什么不能使用%v来打印int和string

70

我知道打印 int 可以使用 %d,而 string 可以使用 %s, 但我们仍然可以使用 %v 来打印它们。那么如果我总是使用 %v 来打印它们会有什么问题呢?


我发现使用%v可能会出现递归 https://play.golang.org/p/4HTN6U4DVU - harrycmfan
你正在覆盖A的String()方法,当你将a转换为字符串时,它将被调用。在String()内部使用%v尝试转换类型为A的a会触发递归调用。永远不要在该类型的String()内部使用%v。 - M. Gopal
1个回答

86

不会发生任何不好的事情,但是%d动词指示fmt包将其作为数字(使用十进制)打印出来,而%v动词表示使用默认格式,该格式可以被覆盖。

看这个例子:

type MyInt int

func (mi MyInt) String() string {
    return fmt.Sprint("*", int(mi), "*")
}

func main() {
    var mi MyInt = 2
    fmt.Printf("%d %v", mi, mi)
}

输出结果(在Go Playground上进行尝试):

2 *2*

当使用%v动词时,fmt包会检查该值是否实现了fmt.Stringer接口(单个String() string方法),如果是,则调用该方法将该值转换为string(如果指定了标志,则可能进一步格式化)。
完整的格式规则列表在fmt包文档中,引用相关部分:

除非使用%T和%p动词打印,否则对于实现某些接口的操作数,应用特殊的格式化考虑。按应用顺序:

  1. 如果操作数是reflect.Value,则将其替换为它所持有的具体值,并继续打印下一个规则。

  2. 如果操作数实现了Formatter接口,则将调用它。Formatter提供了格式化的精细控制。

  3. 如果使用#标志(%#v)并且操作数实现了GoStringer接口,则将调用该接口。

如果格式(对于Println等隐式为%v)对于字符串有效(%s %q %v %x %X),则适用以下两个规则:

  1. 如果操作数实现了error接口,则将调用Error方法将对象转换为字符串,然后按所需的动词(如果有)格式化。

  2. 如果操作数实现了String() string方法,则将调用该方法将对象转换为字符串,然后按所需的动词(如果有)格式化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接