如何在控制台中打印结构体变量?

708

如何在 Golang 中将此结构体的 IdTitleName 等内容打印(输出)到控制台?

type Project struct {
    Id      int64   `json:"project_id"`
    Title   string  `json:"title"`
    Name    string  `json:"name"`
    Data    Data    `json:"data"`
    Commits Commits `json:"commits"`
}

3
所有的调试信息?尝试使用fmt.Println - Ry-
2
我非常喜欢使用 spew https://github.com/davecgh/go-spew - Ramakanth Reddy
2
https://github.com/hexops/valast 是一个比 go-spew 更好且最新的替代方案。 - Mihai Todor
31个回答

1190

打印结构体字段的名称:

fmt.Printf("%+v\n", yourProject)

fmt 中得知:
在打印结构体时,加号标志(%+v)会添加字段名。
这假设你有一个 Project 的实例(在 'yourProject' 中)。
文章 JSON and Go 将详细介绍如何从 JSON 结构中检索值。
这个 Go by example 页面 提供了另一种技术:
type Response2 struct {
  Page   int      `json:"page"`
  Fruits []string `json:"fruits"`
}

res2D := &Response2{
    Page:   1,
    Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))

这将会输出:

{"page":1,"fruits":["apple","peach","pear"]}

如果您没有任何实例,那么您需要使用反射来显示给定结构体的字段名称,就像这个例子一样。

要了解更多有关反射的信息,请参阅这篇文章

type T struct {
    A int
    B string
}

t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()

for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    fmt.Printf("%d: %s %s = %v\n", i,
        typeOfT.Field(i).Name, f.Type(), f.Interface())
}

2
谢谢你的回答,但还有一件事情。 我的JSON文件与API相关......因此我不想设置Id或Name,我只想通过API获取并在控制台中打印它。我该怎么做呢? - fnr
7
如果你有一个 JSON 文档,你需要进行反序列化处理(unmarshall),才能够打印出它的字段。 - VonC
6
点赞!我的唯一抱怨是%+v命令没有漂亮的打印输出!不过我对这行代码的效率还是很满意的。 - Shadoninja
3
需要使用 "encoding/json" 导入库来实现 JSON 编组技术。 - Jim Hoagland
4
请注意,.Printf("%+v\n") 也适用于 "log" 包。 - Ariel Monaco
显示剩余5条评论

212

我想推荐go-spew,根据他们在 Github 上的描述,这个工具“实现了一个深度漂亮打印机,以帮助调试 Go 数据结构。”

go get -u github.com/davecgh/go-spew/spew

使用示例:

package main

import (
    "github.com/davecgh/go-spew/spew"
)

type Project struct {
    Id      int64  `json:"project_id"`
    Title   string `json:"title"`
    Name    string `json:"name"`
    Data    string `json:"data"`
    Commits string `json:"commits"`
}

func main() {

    o := Project{Name: "hello", Title: "world"}
    spew.Dump(o)
}

输出:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}

6
你可以添加 go-spew 中的取消引用功能。这使你能够打印指针所引用的结构体的值,而不是指针本身。 - user4962466
1
使用spew的最大优点是输出已经格式化良好,因此您可以轻松检查所有对象属性。 - COil

199

我的建议是使用json.MarshalIndent——令人惊讶的是,这并没有被建议,因为它是最直接的方法。例如:

func prettyPrint(i interface{}) string {
    s, _ := json.MarshalIndent(i, "", "\t")
    return string(s)
}

没有外部依赖项,输出结果格式良好。

3
正是我在寻找的。利用内置的JSON库,轻松漂亮地打印输出。 - AdmiralThrawn
2
除非需要打印字段类型和长度(Spew非常适合此用途),否则此解决方案是最佳的,因为指针也可以正确打印! - Christophe Vidal
7
值得注意的是,Marshal() 只序列化结构体中被导出的字段 -- 但对于映射来说非常完美。 - Brent Bradburn
1
最佳答案。 - Hu Xixi
如果你使用Unix系统,你可以将其通过管道传递给jq,以获得更美观的JSON输出。 - undefined
显示剩余5条评论

49

如果您想要对一个 struct 进行格式化输出,我认为最好实现一个自定义的字符串函数。

例如:

package main

    import "fmt"

    type Project struct {
        Id int64 `json:"project_id"`
        Title string `json:"title"`
        Name string `json:"name"`
    }

    func (p Project) String() string {
        return fmt.Sprintf("{Id:%d, Title:%s, Name:%s}", p.Id, p.Title, p.Name)
    }

    func main() {
        o := Project{Id: 4, Name: "hello", Title: "world"}
        fmt.Printf("%+v\n", o)
    }

27
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type

2
fmt.Printf(%#v, p) 抛出了 main.structstruct type,请问 "%#v""%+v" 有什么区别?@cokebol - muthukumar selvaraj
"%+v":这将为您提供未解组的值以及它们的字段名称。 "%#v":这将给出值以及它们的类型/签名。例如:p:= Project {Id:4,Name:“hello”,Title:“world”} “%+v”的输出:{Id:4 Title:world Name:hello} “%#v”的输出:main.Project {Id:4,Title:“world”,Name:“hello”} - Gaurav

27

或者,尝试使用这个函数 PrettyPrint()

// print the contents of the obj
func PrettyPrint(data interface{}) {
    var p []byte
    //    var err := error
    p, err := json.MarshalIndent(data, "", "\t")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%s \n", p)
}

为了使用这个功能,您不需要任何额外的包,除了fmtencoding/json之外,只需引用、指向或字面上创建的结构体即可。
要使用,只需获取您的结构体,在主函数中初始化它或在您所在的任何包中,并将其传递给PrettyPrint()
type Prefix struct {
    Network string
    Mask    int
}

func valueStruct() {
    // struct as a value
    var nw Prefix
    nw.Network = "10.1.1.0"
    nw.Mask = 24
    fmt.Println("### struct as a pointer ###")
    PrettyPrint(&nw)
}

它的输出结果将会是:
### struct as a pointer ###
{
    "Network": "10.1.1.0",
    "Mask": 24
} 

在这里玩弄代码


16

我建议您使用 fmt.Printf("%#v\n", s) ,这将同时打印出 Golang 的类型。

package main

import (
    "fmt"
    "testing"
)

type student struct {
    id   int32
    name string
}

type Project struct {
    Id      int64   `json:"project_id"`
    Title   string  `json:"title"`
    Name    string  `json:"name"`
}

func TestPrint(t *testing.T) {
    s := Project{1, "title","jack"}
    fmt.Printf("%+v\n", s)
    fmt.Printf("%#v\n", s)
}

结果:

{Id:1 Title:title Name:jack}
main.Project{Id:1, Title:"title", Name:"jack"}

16

使用 fmt 包进行输出非常方便:

fmt.Printf("%+v \n", yourProject)

如果想查看结构体的完整类型,可以使用#替换+:

fmt.Printf("%#v \n", yourProject) 

11

我建议使用Pretty Printer Library。使用这个库,你可以非常容易地打印任何结构。

  1. 安装库

    https://github.com/kr/pretty

或者

go get github.com/kr/pretty

现在在你的代码中像这样操作

package main

import (
fmt
github.com/kr/pretty
)

func main(){

type Project struct {
    Id int64 `json:"project_id"`
    Title string `json:"title"`
    Name string `json:"name"`
    Data Data `json:"data"`
    Commits Commits `json:"commits"`
}

fmt.Printf("%# v", pretty.Formatter(Project)) //It will print all struct details

fmt.Printf("%# v", pretty.Formatter(Project.Id)) //It will print component one by one.

}

这个库可以让你获取组件之间的差异,而且还有更多功能。你也可以在这里查看库的文档


2
看看由pretty.Formatter生成的输出示例会很有帮助。 - Konstantin Tikhonov

10

我喜欢 litter

以下是它们的自述文件:

type Person struct {
  Name   string
  Age    int
  Parent *Person
}

litter.Dump(Person{
  Name:   "Bob",
  Age:    20,
  Parent: &Person{
    Name: "Jane",
    Age:  50,
  },
})

Sdump在测试中非常方便:

func TestSearch(t *testing.T) {
  result := DoSearch()

  actual := litterOpts.Sdump(result)
  expected, err := ioutil.ReadFile("testdata.txt")
  if err != nil {
    // First run, write test data since it doesn't exist
        if !os.IsNotExist(err) {
      t.Error(err)
    }
    ioutil.Write("testdata.txt", actual, 0644)
    actual = expected
  }
  if expected != actual {
    t.Errorf("Expected %s, got %s", expected, actual)
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接