为什么在Golang中使用fmt.Println(slice)打印切片是不同的

5 go

代码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
Run Code Online (Sandbox Code Playgroud)

输出A:

[0 1 2 3 4 5 6 7 8 9]
Run Code Online (Sandbox Code Playgroud)

代码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." }
Run Code Online (Sandbox Code Playgroud)

输出B:

this is called.
Run Code Online (Sandbox Code Playgroud)

为什么fmt.Println(slice)这两个代码(A和B)的行为不同?
或为什么自动fmt.Println(slice)打电话slice.Error()

Tim*_*per 7

这被记录fmt(强调我的)行为的一部分:

除非使用动词%T和%p打印,否则特殊格式注意事项适用于实现某些接口的操作数.按申请顺序:

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

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

  3. 如果%v动词与#flag(%#v)一起使用,并且操作数实现了GoStringer接口,则将调用该接口.

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

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

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

对于复合操作数(如切片和结构),格式以递归方式应用于每个操作数的元素,而不是作为整体应用于操作数.因此,%q将引用一个字符串片段的每个元素,%6.2f将控制浮点数组的每个元素的格式.

所述fmt包看到该slice工具error和打印value.Error(),而不是遍历切片以及将格式化到每个元素.