为什么Error()优先于String()?

4
我一直在阅读有关Go语言的教程,但我无法弄清楚为什么会出现这种情况。
当你拥有一个Stringer(String() string)时,fmt将使用该方法来打印到控制台。就像https://tour.golang.org/methods/6中所建议的那样。
但是,如果添加Error() string,则会调用该方法而不是String() string。
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func (p *Person) String() string {
    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func (p *Person) Error() string {
    return fmt.Sprintf("Failed")
}

func main() {
    a := &Person{"Arthur Dent", 42}
    z := &Person{"Zaphod Beeblebrox", 9001}
    fmt.Println(a, z)
}

结果:

失败 失败

我不明白为什么fmt.Println使用Error而不是String

2个回答

9
仅仅因为这是它的实现方式。在实践中,error 更加重要,所以如果实现了 error 接口,就会打印出错误信息。
这个已经有文档记录了,可以阅读 fmt 包的文档:

除使用 %T 和 %p 动词外,对于实现某些接口的操作数,适用特殊格式化考虑因素。按照应用顺序:

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

  2. 如果使用 %v 动词和 # 标记(%#v),并且操作数实现了 GoStringer 接口,则将调用它。

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

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

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

因此,error 接口是第三个被考虑的,而 String() 只是第四个。

2
原因很简单:当 fmt 使用它的任意一个打印函数时,它会对每个参数进行类型切换以确定该如何打印,而在这个类型切换中,case error 出现在 case Stringer 之前。

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