string - 如何使用字段的 String() 打印结构?

标签 string go struct

这段代码:

type A struct {
    t time.Time
}

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

打印:

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

A 未实现 String(),因此它不是 fmt.Stringer 并打印其 native 表示。但是为我想要打印的每个结构体实现 String() 是非常乏味的。更糟糕的是,如果我添加或删除某些字段,我必须更新 String()。有没有更简单的方法来打印结构及其字段的 String()

最佳答案

这就是 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()
}

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

fmt.Println(PrintStruct(a, true))

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

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

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

注意事项:

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

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

测试它:

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

输出(在 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 - 如何使用字段的 String() 打印结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33142594/

相关文章:

java - 比较对象数组中的字符串

go - 为什么 golang reflect.MakeSlice 返回不可寻址的值

go - 如何从 LoRa App 服务器接收数据?

sql - 转到数据库连接器 : go-sql-driver works, 其他一切 "unknown driver, forgotten import?"

c - Malloc 改变 C 中的值

c++ - 无法将结构类型的元素添加到 vector 中?

c# - 获取路径的最后一个字段?

c# - 用于查找和删除重复单词的正则表达式

android - textview 上的颜色和样式操作

C:输出错误链表和写入和读取文件