英文:
Why does Error() have priority over String()
问题
我一直在查看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)
}
结果:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论