如何使用String()字段打印struct?

Lai*_*uan 8 string struct go

这段代码:

type A struct {
    t time.Time
}

func main() {
    a := A{time.Now()}
    fmt.Println(a)
    fmt.Println(a.t)
}
Run Code Online (Sandbox Code Playgroud)

打印:

{{63393490800 0 0x206da0}}
2009-11-10 23:00:00 +0000 UTC
Run Code Online (Sandbox Code Playgroud)

A没有实现String(),所以它不是一个fmt.Stringer并打印其原生代表.但是String()对于我想要打印的每个结构实现起来都非常繁琐.更糟糕的是,String()如果我添加或删除某些字段,我必须更新s.是否有更简单的方法来打印结构,其字段String()是?

icz*_*cza 4

这就是fmt包的实现方式,因此您无法更改它。

但是您可以编写一个辅助函数,它使用反射(reflect包)来迭代结构体的字段,并且可以String()在字段上调用该方法(如果它们有这样的方法)。

实施示例:

func PrintStruct(s interface{}, names bool) string {
    v := reflect.ValueOf(s)
    t := v.Type()
    // To avoid panic if s is not a struct:
    if t.Kind() != reflect.Struct {
        return fmt.Sprint(s)
    }

    b := &bytes.Buffer{}
    b.WriteString("{")
    for i := 0; i < v.NumField(); i++ {
        if i > 0 {
            b.WriteString(" ")
        }
        v2 := v.Field(i)
        if names {
            b.WriteString(t.Field(i).Name)
            b.WriteString(":")
        }
        if v2.CanInterface() {
            if st, ok := v2.Interface().(fmt.Stringer); ok {
                b.WriteString(st.String())
                continue
            }
        }
        fmt.Fprint(b, v2)
    }
    b.WriteString("}")
    return b.String()
}
Run Code Online (Sandbox Code Playgroud)

现在,当您想打印 a 时struct,您可以执行以下操作:

fmt.Println(PrintStruct(a, true))
Run Code Online (Sandbox Code Playgroud)

您还可以选择向结构添加一个String()方法,该方法只需调用我们的PrintStruct()函数:

func (a A) String() string {
    return PrintStruct(a, true)
}
Run Code Online (Sandbox Code Playgroud)

每当您更改结构时,您都不必对String()方法执行任何操作,因为它使用反射来动态遍历所有字段。

笔记:

由于我们使用反射,因此您必须导出t time.Time该字段才能使其工作(还添加了一些额外的字段以用于测试目的):

type A struct {
    T          time.Time
    I          int
    unexported string
}
Run Code Online (Sandbox Code Playgroud)

测试它:

a := A{time.Now(), 2, "hi!"}
fmt.Println(a)
fmt.Println(PrintStruct(a, true))
fmt.Println(PrintStruct(a, false))
fmt.Println(PrintStruct("I'm not a struct", true))
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上尝试):

{T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!}
{T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!}
{2009-11-10 23:00:00 +0000 UTC 2 hi!}
I'm not a struct
Run Code Online (Sandbox Code Playgroud)