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

huangapple go评论85阅读模式
英文:

Why does Error() have priority over String()

问题

我一直在查看Go语言的教程,但是我无法弄清楚为什么会出现这种情况。

当你有一个StringerString() 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)
}

结果:

Failed Failed

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

英文:

I've been looking through the tour for go, and I can't figure out why this happens.

When you have a Stringer (String() string), fmt will use that method for printing to console. Like suggested in https://tour.golang.org/methods/6

However if you add Error() string, this method gets called instead of 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)
}

Results:

> Failed Failed

I don't understand why fmt.Println uses Error instead of String.

答案1

得分: 9

这是因为这样实现的。在实践中,"error"更重要,所以如果实现了"error"接口,就会打印它。

这在文档中有说明,请阅读fmt的包文档:

> 除非使用%T和%p这两个动词打印,否则对于实现了特定接口的操作数,会应用特殊的格式化规则。应用规则的顺序如下:
>
> 1. 如果操作数实现了Formatter接口,将会调用该接口。Formatter接口提供了对格式化的精细控制。
>
> 2. 如果使用%v动词并带有#标志(%#v),并且操作数实现了GoStringer接口,将会调用该接口。
>
> 如果格式(对于Println等隐式为%v)对于字符串是有效的(%s %q %v %x %X),则遵循以下两个规则:
>
> 3. 如果操作数实现了error接口,将会调用Error方法将对象转换为字符串,然后按照动词的要求进行格式化(如果有的话)。
>
> 4. 如果操作数实现了方法String() string,将会调用该方法将对象转换为字符串,然后按照动词的要求进行格式化(如果有的话)。

所以,"error"在列表中排在第三位,而"String()"只排在第四位。

英文:

Simply because this is how it is implemented. An error is more important in practice, so if the error interface is implemented, that will be printed.

This is documented, read the package doc of fmt:

> Except when printed using the verbs %T and %p, special formatting considerations apply for operands that implement certain interfaces. In order of application:
>
> 1. If an operand implements the Formatter interface, it will be invoked. Formatter provides fine control of formatting.
>
> 2. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked.
>
> If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:
>
> 3. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
>
> 4. If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).

So error is 3<sup>rd</sup> on the list while String() is only 4<sup>th</sup>.

答案2

得分: 2

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

英文:

The reason is simple: when fmt uses any of it's print functions, it does a type switch for each argument to determine how it should be printed, and in that type switch case error appears just before case Stringer.

huangapple
  • 本文由 发表于 2015年5月11日 13:05:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/30159980.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定