当前位置: 首页 > 面试题库 >

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

鲍俊杰
2023-03-14
问题内容

这段代码:

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(),因此它不是a
fmt.Stringer并打印其本机表示形式。但是String()对于我要打印的每个结构都非常繁琐。更糟糕的是,String()如果添加或删除某些字段,则必须更新。有没有更简单的方法来打印带有其字段的结构的结构String()


问题答案:

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

但是,您可以编写一个使用反射(reflect包)来遍历struct的字段的辅助函数,并可以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


 类似资料:
  • 问题内容: http://play.golang.org/p/joEmjQdMaS 这样会打印一个内存地址 有没有办法打印它: 这主要是出于调试目的,如果我有一个带有30个指针字段的结构,我不想为30个字段中的每一个都执行一个println来查看其中的内容。 问题答案: 有一个很棒的软件包,称为go-spew。正是您想要的。 将为您提供以下输出:

  • 我刚接触JasperReports,在解决一个问题时遇到了问题。 我有一份报告和一个字段,它是

  • 问题内容: 我知道如何对一维字符串数组执行此方法,但是如何打印二维数组?使用1D时,我是这样进行的: 如何打印2D阵列? 问题答案: 您只需对元素进行两次迭代: 重要提示: 也很有用,因为您可以链接操作,例如:因为它返回对self的引用!如果可以的话,使用晕厥糖。 重要事项2: 由于在这种情况下,您计划向其添加许多内容,因此最好估算一下避免在添加过程中多次分配和重新定位数组的能力,因此您可以执行以

  • 问题内容: 我正在尝试学习如何将软件包与go-sql-driver一起使用。我编写了以下简单程序,它可以工作,但是我无法弄清楚如何打印多个字段。 该数据库具有三个字段,和。我查询“ title1”,这是值之一,但我想打印“ title”和“ body”的值。我该怎么办? 问题答案: 要读取和而不是,请首先更改该语句。 更改 至 然后更改读数。更改 至 这将读取两个列。 要打印字段,您可以执行

  • 问题内容: 如何获得要打印到[标准输出]的JUnit断言的结果? 我有一些像这样的测试: 这是我希望获得的打印输出格式: 是否可以使用和进行此操作?或是否存在任何,方法? 问题答案: 首先,您有两个问题,而不是一个。断言失败时,将引发异常。这样可以防止检查超过此点的任何断言。为了解决这个问题,您需要使用ErrorCollector。 其次,我不认为JUnit内置了任何方法来执行此操作。但是,您可以

  • 问题内容: 我想使用PDFBox打印 由iText创建的 PDF文件 。我已经使用PDDocument类及其方法print()成功尝试了此操作。您可以在此处找到文档: http //pdfbox.apache.org/apidocs/。 (我正在使用此代码:) 方法print()很好用,但是 有一个问题:当我需要打印多个文件时,该方法要求我为每个文档选择打印机。 有什么办法只能设置一次打印机吗?