为什么%v为嵌套结构打印出意外的值?

时间:2018-10-29 14:48:38

标签: go

当打印带有实现了String()的嵌套结构的结构时,根据我们的理解,%v格式将打印“意外”值。

下面是代码段。

package main

import (
  "fmt"
)

type Inner struct {
}

type A struct {
    Inner
    FieldA string
}

func (i Inner) String() string {
    return "anything"
}

func main() {
    myA := A{FieldA: "A"}
    fmt.Printf("%v", myA)
}

我们希望输出为

  

{任何A}

但是实际结果是

  

任何东西

为什么会这样?似乎FieldA被忽略了吗?更令人困惑的是,如果我们有两个嵌套结构,其中两个结构都实现了String(),则将得到预期的输出。

package main

import (
  "fmt"
)

type Inner struct {
}

type InnerAgain struct {
}

type A struct {
    Inner
    InnerAgain
    FieldA string
}

func (i Inner) String() string {
    return "anything"
}

func (i InnerAgain) String() string {
    return "nothing"
}

func main() {
    myA := A{FieldA: "A"}
    fmt.Printf("%v", myA)
}

输出为

  

{什么都没有A}

...

2 个答案:

答案 0 :(得分:6)

由于您嵌入Inner,因此您固有的所有属性-包括String()-函数。因此%v实际上是在呼叫Inner.String()

从文档(https://golang.org/pkg/fmt/):

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

答案 1 :(得分:1)

因为fmt软件包将%v的规则表示为:

  

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

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

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

  4.   

因此,%v实际上将String()方法用于更严格的参数。