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

时间:2016-07-13 20:47:24

标签: 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

输出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()

1 个答案:

答案 0 :(得分:7)

这是documented作为fmt(强调我的)行为的一部分:

  

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

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

  2.   
  3. 如果操作数实现了Formatter接口,则会调用它。 Formatter可以很好地控制格式化。

  4.   
  5. 如果%v动词与#flag(%#v)一起使用,并且操作数实现了GoStringer接口,那么将调用它。

         

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

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

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

  10.         

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

fmt包看到slice实现error并打印value.Error(),而不是遍历切片并对每个元素应用格式。