在调式 Go 程序时,我们经常想知道对象的内部数据是什么样了,以便掌握程序的运行情况。

一般有两种做法:对于简单的代码测试,我们可以通过fmt包来打印一些对象信息;在稍复杂场景下,可以利用调式器来完成,例如 GDB、LLDB 和 Delve 等。

但是,这两种做法都有不足之处。fmt包能打印的信息并不友好,尤其在结构体中含有指针对象时;通过调式器来调式程序也经常受限于各种因素,例如远程访问服务器。

示例

对于 fmt 包的能力短板,我们来看一个例子。

定义 Instance 和 Inner 结构体,其中 Instance 的C属性字段是 Inner 类型指针。

type Instance struct {A stringB intC *Inner
}type Inner struct {D stringE string
}

实例化一个 Instance 对象ins

func main() {ins := Instance{A: "AAAA",B: 1000,C: &Inner{D: "DDDD",E: "EEEE",},}fmt.Println(ins)
}

此时,我们想知道ins的内部数据。通过fmt.Println(ins)语句得到的打印信息如下

{AAAA 1000 0xc000054020}

由于 C 字段是指针,所以打印出来的是一个地址0xc000054020,而地址背后的数据却被隐藏了。显然,这对程序排查非常不友好。

go-spew

go-spew 就是为了解决上述问题而生的,它为 Go 数据结构实现了一个深度打印机。

同样以上文代码为例,这次使用 go-spew 进行打印。

下载

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

导包

"github.com/davecgh/go-spew/spew"

打印

func main() {ins := Instance{A: "AAAA",B: 1000,C: &Inner{D: "DDDD",E: "EEEE",},}spew.Dump(ins)
}

得到打印结果

(main.Instance) {A: (string) (len=4) "AAAA",B: (int) 1000,C: (*main.Inner)(0xc0000ba0c0)({D: (string) (len=4) "DDDD",E: (string) (len=4) "EEEE"})
}

是不是非常详细?

场景扩展

指针数组

除了结构体中含有指针对象时打印 fmt 打印不够清晰,如果数组或者map中是指针对象时,传统的打印同样不友好。

type Demo struct {a intb string
}func main() {arr := [...]*Demo{{100, "Python"}, {200, "Golang"}}fmt.Printf("%v\n-----------------分割线-----------\n", arr)spew.Dump(arr)
}

两种打印的输出结果对比

[0xc00011c018 0xc00011c030]
-----------------分割线-----------
([2]*main.Demo) (len=2 cap=2) {(*main.Demo)(0xc00011c018)({a: (int) 100,b: (string) (len=6) "Python"}),(*main.Demo)(0xc00011c030)({a: (int) 200,b: (string) (len=6) "Golang"})
}

孰强孰弱,一目了然。

循环结构

通过 spew.Dump 方法可以将指针地址和它指向的数据都打印出来,那如果 go-spew 需要打印循环数据结构怎么办,它能否正确处理(而不是陷入无限循环)?

定义循环结构体对象 Circular

type Circular struct {a    intnext *Circular
}

实例化循环结构体对象,再分别通过 fmt 和 go-spew 进行打印对比

func main() {c := &Circular{1, nil}c.next = &Circular{2, c}fmt.Printf("%+v\n----------------分割线-------------------\n", c)spew.Dump(c)
}

得到结果

&{a:1 next:0xc0000962f0}
----------------分割线-------------------
(*main.Circular)(0xc0000962e0)({a: (int) 1,next: (*main.Circular)(0xc0000962f0)({a: (int) 2,next: (*main.Circular)(0xc0000962e0)(<already shown>)})
})

再次证明 go-spew 的强大。

总结

go-spew 借助于 unsafe 包,为我们带来了非常漂亮的打印功能。

当然,go-spew 不止 Dump 方法,它也提供了其他方法,例如转换为字符串的 Sdump 方法;输出重定向的 Fdump 方法;与 fmt 类似的一套 Print 用法。

同时,可以通过 spew.Config 进行一些参数配置,例如设置 spew.Config.MaxDepth 用于控制打印深度。

调式 Go 程序时,go-spew 是一个非常好用的助手工具,推荐大家使用。

感谢你的点赞在看哦~

看透 Go 对象内部细节的神器相关推荐

  1. asp.NET自定义服务器控件内部细节系列教程四

    如大家要转载,请保留本人的版权: /* *Description:asp.NET自定义服务器控件内部细节系列教程 *Auther:崇崇-天真的好蓝 *MSN:chongchong2008@msn.co ...

  2. asp.NET自定义服务器控件内部细节系列教程五

    如大家要转载,请保留本人的版权: /* *Description:asp.NET自定义服务器控件内部细节系列教程 *Auther:崇崇-天真的好蓝 *MSN:chongchong2008@msn.co ...

  3. easyui form提交和formdata提交记录,查看FormData对象内部的值

    1  easyui form提交 $('form').form('submit',{url:'';onSubmit:'';success:function(data){//这种方法获取到的data是字 ...

  4. asp.NET自定义服务器控件内部细节系列教程一

    如大家要转载,请保留本人的版权: /* *Description:asp.NET自定义服务器控件内部细节系列教程 *Auther:崇崇-天真的好蓝 *MSN:chongchong2008@msn.co ...

  5. 在对象内部尽量直接訪问实例变量 --Effictive Objective-C 抄书

    在对象之外訪问实例变量时,应该总是通过属性来做.在那么在对象内部訪问实例变量的时候,又该怎样呢? 这是 OCer们一直激烈讨论的问题.有人觉得,不管什么情况,都应该通过属性来訪问实例变量;也有人说,& ...

  6. 超级计算机怎么收费,近距离看中国天河2号内部细节及收费标准

    [PConline 资讯]天河2的报道已经不少,参数露的也差不多了(可以参考延伸阅读中我们的报道),但是对于这部全球最快超级计算机真实的内部细节,一直还笼罩着一团迷雾,特别是升级了"ARCH ...

  7. 在对象内部尽量直接访问实例变量 --Effictive Objective-C 抄书

    在对象之外访问实例变量时,应该总是通过属性来做.在那么在对象内部访问实例变量的时候,又该如何呢? 这是 OCer们一直激烈讨论的问题.有人认为,无论什么情况,都应该通过属性来访问实例变量;也有人说,& ...

  8. 【Effection C++】读书笔记 条款28:避免返回handles指向对象内部成分

    [Effective C++]读书笔记 Part5 实现 条款28:避免返回handles指向对象内部成分 避免返回handles(包括references,指针,迭代器)指向对象内部.遵守这个条款可 ...

  9. python魔法属性_查看对象内部属性的名称和值,Python“魔法”属性__dict__的使用...

    我们知道,Python中"一切皆对象",Python是一门真正意义上面向对象的编程语言.因此,如果对对象内部存储结构了解不深入,在学习Python的道路上是没有办法进阶的.今天,我 ...

最新文章

  1. springmvc 配置多个数据源,并动态切换
  2. C++中函数参数的默认值
  3. Centos7使用yum源安装mysql5.7和redis
  4. 一天学完spark的Scala基础语法教程八、集合(idea版本)
  5. asp.net如何生成图片验证码
  6. 10个业界最流行的Kubernetes发行版
  7. 通过jQuery把数据库里面的数据进行增删查改
  8. jquery.js和jquery-1.4.2.min.js的区别
  9. Promise的链式调用三种写法,Promise.all与式调用
  10. 被3亿农民力挺,仍惨遭封杀!中国最冤产品,出路在哪?
  11. 非常实用的设计类导航
  12. linux去重统计个数,linux 文件内容查找、去重、统计(示例代码)
  13. C++ string类相关函数
  14. 20个你可能不知道的 Linux 网络工具
  15. CListCtrl 类中InsertItem, InsertColumn, SetItemText 的使用
  16. 物联网|ZETA技术助力远超抄表实现智能化、精细化
  17. 数据结构_静态链表(C语言)
  18. oracle siebel crm 8.0,Solix实现Oracle Siebel CRM 8.1整合
  19. 腾讯地图路线规划 vue
  20. 根据经纬度获取地址(逆地址解析)

热门文章

  1. html追加datatype,jquery ajax中dataType的设置问题
  2. 使用 GraalVM 将基本的 Java 项目打包成 EXE
  3. crontab清理日志
  4. [译] 标准化的包布局(Standard Package Layout)
  5. (PCB)进程控制块
  6. Windows环境下QWT安装及配置
  7. Spring boot 多数据源
  8. mysql 导入导出.sql文件
  9. 修改ECSHOP,支持图片云存储化(分离到专用图片服务器)
  10. **16.app后端如何保证通讯安全--url签名