代码A:
package main
import "fmt"
func main() {
slice := IntSlice{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(slice)
}
type IntSlice []int
输出A:
[0 1 2 3 4 5 6 7 8 9]
代码B:
package main
import "fmt"
func main() {
slice := IntSlice{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(slice)
}
type IntSlice []int
func (slice IntSlice) Error() string { return "this is called." }
输出B:
this is called.
为什么这两个代码(A和B)fmt.Println(slice)
的行为不同?
或为什么fmt.Println(slice)
会自动调用slice.Error()
?
答案 0 :(得分:7)
这是documented作为fmt
(强调我的)行为的一部分:
除非使用动词%T和%p打印,否则特殊格式注意事项适用于实现某些接口的操作数。按申请顺序:
如果操作数是reflect.Value,则操作数将替换为它所拥有的具体值,并继续打印下一个规则。
如果操作数实现了Formatter接口,则会调用它。 Formatter可以很好地控制格式化。
如果%v动词与#flag(%#v)一起使用,并且操作数实现了GoStringer接口,那么将调用它。
如果格式(对于Println等隐式%v)对字符串有效(%s%q%v%x%X),则适用以下两条规则:
如果操作数实现了错误接口,则将调用Error方法将对象转换为字符串,然后根据动词的需要对其进行格式化(如果有)。
- 醇>
如果操作数实现方法String()字符串,则将调用该方法将对象转换为字符串,然后根据动词的需要对其进行格式化(如果有)。
对于复合操作数(如切片和结构),格式以递归方式应用于每个操作数的元素,而不是作为整体应用于操作数。因此,%q将引用一个字符串片段的每个元素,%6.2f将控制浮点数组的每个元素的格式。
fmt
包看到slice
实现error
并打印value.Error()
,而不是遍历切片并对每个元素应用格式。