如何使用字段的String()打印结构? [英] How to print struct with String() of fields?

查看:105
本文介绍了如何使用字段的String()打印结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段代码:

  type A struct {
t time.Time
}

func main(){
a:= A {time.Now()}
fmt.Println(a)
fmt.Println(at)
}

打印:

  {{63393490800 0 0x206da0}} 
2009-11-10 23:00:00 +0000 UTC

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

解决方案

这是 fmt 包的实现方式,所以你不能改变它。



<但是你可以写一个使用反射的帮助函数( reflect 包)来遍历结构的字段,并且如果它们有这样一个方法,可以调用字段上的 String()方法。



示例实现:

  func PrintStruct(s interface {},names bool)字符串{
v:= reflect.ValueOf(s)
t:= v.Type()
//如果s不是struct,则避免恐慌:
if t.Kind )!= reflect.Struct {
return fmt.Sprint(s)
}

b:=&; bytes.Buffer {}
b.WriteString({ )
for i:= 0;我< v.NumField(); i ++ {
if i> 0 {
b.WriteString()
}
v2:= v.Field(i)
如果名称{
b.WriteString(t.Field i).Name)
b.WriteString(:)
}
if v2.CanInterface(){
if st,ok:= v2.Interface()。( fmt.Stringer); (b,v2)
} $ b { $ b b.WriteString(})
return b.String()
}

现在当你想打印一个 struct 时,你可以这样做:

  fmt.Println(PrintStruct(a,true))

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



$ p $ func(a A)String()string {
return PrintStruct(a,true)
}

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



注释:



由于我们使用的是反射,因此您必须将 t time.Time 字段导出为这个工作(也为测试目的添加了一些额外的字段):

  type A struct {
T time。时间
我int
未导出的字符串
}

测试它:

  a:= A {time.Now(),2,hi!} 
fmt.Println a)
fmt.Println(PrintStruct(a,true))
fmt.Println(PrintStruct(a,false))
fmt.Println(PrintStruct(我不是结构体 ,真))

输出(尝试在

  {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!}
我不是结构体


This code:

type A struct {
    t time.Time
}

func main() {
    a := A{time.Now()}
    fmt.Println(a)
    fmt.Println(a.t)
}

prints:

{{63393490800 0 0x206da0}}
2009-11-10 23:00:00 +0000 UTC

A doesn't implement String(), so it's not a fmt.Stringer and prints its native representation. But is very tedious to implement String() for every single struct I want to print. Worse, I have to update the String()s if I add or remove some fields. Is there an easier way to print a struct, with its fields' String()s?

This is how the fmt package is implemented, so you can't change that.

But you can write a helper function which uses reflection (reflect package) to iterate over the fields of a struct, and can call the String() method on the fields if they have such a method.

Example implementation:

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()
}

Now when you want to print a struct, you can do:

fmt.Println(PrintStruct(a, true))

You may also choose to add a String() method to your struct which just has to call our PrintStruct() function:

func (a A) String() string {
    return PrintStruct(a, true)
}

Whenever you change your struct, you don't have to do anything with your String() method as it uses reflection to dynamically walk over all the fields.

Notes:

Since we're using reflection, you have to export the t time.Time field for this to work (also added a few extra fields for testing purposes):

type A struct {
    T          time.Time
    I          int
    unexported string
}

Testing it:

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))

Output (try it on the 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

这篇关于如何使用字段的String()打印结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆