这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战
本文针对 Golang 的结构体字段的打印进行一些研究。其中涉及到一些反射的知识。实际上本文是基于前面积累的反射进行综合使用的一个示例,也在工作中使用着。
问题提出
总结一些实践情况,结构体字段值的输出还是比较常见的,至少笔者目前常用。比如输出某些数据表的数据(代码中会转换为结构体),对比不同版本数据表的数据,对比某些不同版本但格式相同的 json 文件,等。为了优化代码,减少开发维护工作量,需寻找一种高效的方法,打印结构体。初步需求如下:
- 格式化,目前需迎合 markdown 表格的格式。
- 接口可通用于数组、map等结构,原则上直接传递某个变量,即可自行输出格式化后的所需内容。
- 输出方式多样化,如输出到终端或文件。
使用 markdown 是因为笔者需要将输出的数据表内容通过 vuepress 发布到内部 web 服务器上,以便随时查阅。
测试数据
本文使用的测试数据如下:
1 | go复制代码type TestObj struct { |
效果
对于可识别渲染 markdown 的平台来说,输出的如下结果:
1 | arduino复制代码print by line - slice default |
就能正常显示表格形式。如下:
print by line - slice default total: 2
Name | Value | Size | Guard |
---|---|---|---|
Jim Kent | 128 | 256 | 56.4 |
James1 | 128 | 259 | 56.4 |
简单版本
遍历结构体数据,并打印之:
1 | css复制代码 for a, b := range objects { |
如果需要格式化,需显式给出结构体字段和格式化形式。如下:
1 | perl复制代码 for a, b := range objects { |
以上结果分别如下:
1 | makefile复制代码0 {Jim | Kent 128 256 56.4} |
由于此版本非吾所用,因此只具大致形式。
可以看到,前者简单,不用理会结构体内容,直接使用%v
即可打印,如需要输出结构体字段名,则用%+v
。但其形式固定的,类似{xx xx xx}
这样。后者使用竖线|
将各字段隔开,需一一写出字段(当然也可忽略部分字段)。
reflect版本
代码如下:
1 | go复制代码func checkSkipNames(a string, b []string) bool { |
上述代码提供的对外接口为PrintStructTable2Buffer
和PrintStructTable
,因为默认格式为markdown
表格形式,故加上Table
。前者输出到缓冲区的(可继续写到文件中),后者直接输出终端。真正实现的接口为PrintStructTable2Buffer
,其提供了自定义标题,和忽略的字段参数,如果不指定标题,必须将title
置为空,因为最后的参数是可变参数,只能有一个,如不写,则输出所有字段。
至于内部实现,因为需要根据用户输入忽略某些字段,因此定义checkSkipNames
检查参数,利用GetStructName
获取结构体名称,GetStructValue
获取结构体的值。不管获取字段还是值,均使用传递的interface{}
,不需额外传递结构体本身。 注意,由于默认使用竖线分隔,如果字段值本身有竖线,则使用<br>
替换——即让该字段的值换行。
测试代码如下:
1 | scss复制代码 // 数组,默认形式 |
测试结果如下:
1 | arduino复制代码print by line - slice default |
观察结果,可达到预期目的。
本文转载自: 掘金