盘点一下结构体标签在Go中的应用
掌握了Go
语言的朋友们应该都知道,在Go
的结构体类型声明里面,字段声明后可以跟一个可选的字符串标签。
type User struct {Name string `json:"name"`
}
上面是一个标准的例子,Name
字段声明中指定了标签json:"name" xml:"name"
,这个标签值看着有点类似Java
程序里给类属性加的注解。
那么这些结构体标签有什么用途呢,我们随便写管用吗?我们平时工作中常用的结构体标签有哪些呢?我们能不能自己定义结构体标签?今天就带大家掰扯清楚这些问题!
结构体标签
Go语言允许我们通过结构体字段标签给一个字段附加可以被反射获取的”元信息“,正好我们上篇文章实战演示Go反射的使用方法和应用场景中讲了Go语言反射使用方法相关的内容,对反射不清楚的可以先去再复习一下。
通常情况下,结构体标签被用于提供结构体字段如何被编码为或者解码自另外一种格式的转换信息(或者是以何种形式被保存至/获取自数据库)。不过,你也可以用它存储任何你想要设置的”元信息“,供其他包或者自己使用。
使用规范
结构体标签在使用上通常是遵守下面三个规范。
结构体标签字符串的值是一个由空格分隔的 key:"value" 对列表,例如:
type User struct {Name string `json:"name" xml:"name"`
}
键,通常表示后面跟的“值”是被哪个包使用的,例如json
这个键会被encoding/json
包处理使用。如果要在“键”对应的“值”中传递多个信息,通常通过用逗号(',')分隔来指定,例如
Name string `json:"name,omitempty"`
按照惯例,如果一个字段的结构体标签里某个键的“值”被设置成了的破折号 ('-'),那么就意味着告诉处理该结构体标签键值的进程排除该字段。例如,把一个字段的标签设置成下面这样
Name string `json:"-"`
就以为进行JSON编码/解码时忽略Name
这个字段。
怎么获取到结构体标签
从一开始我们就说结构体标签是给反射准备的,那么怎么在Go
程序里用反射获得到字段的结构体标签呢?看了我们上一篇文章的同学,应该会知道,结构体字段类型相关的信息,在反射的世界里使用reflect.StructFiled
这个类型表示的。
type StructField struct {Name stringType Type // field typeTag StructTag // field tag string......
}
如上所示,其中包含的Tag
字段即代表了字段声明中的结构体标签信息。让我们通过自定义结构体标签的例子来演示一下怎么使用它在反射里读取到标签里的信息。
用反射获取到自定义的结构体标签
使用反射reflect
包访问结构体字段的标签值,我们需要先获取到结构体的类型信息Type
,然后使用Type.Field(i int)
或 Type.FieldByName(name string)
,方法查询字段信息,这两个方法都会返回一个StructField
类型的值,上面我们也说了它在反射的世界里用于描述一个结构体字段;而StructField.Tag
是一个StructTag
类型的值,它描述了字段的标签。
上面我们谈到了结构体标签的使用规范,如果遵循规范给字段设置了标签后,就可以使用StructTag
的Get
方法解析标签的值并返回你指定的键的“值”。
func (tag StructTag) Get(key string) string
为了方便判断一个给定的key
是否存在与标签中,StructTag
还提供了一个Lookup
方法
func (tag StructTag) Lookup(key string) (value string, ok bool)
跟Get
方法不同的是,Lookup
会通过返回的ok
值告知给定key
是否存在与标签中。
下面通过一个例子,演示下获取我们自定义标签的过程。
package mainimport ("fmt""reflect"
)type User struct {Name string `mytag:"MyName"`Email string `mytag:"MyEmail"`
}func main() {u := User{"Bob", "bob@mycompany.com"}t := reflect.TypeOf(u)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Printf("Field: User.%s\n", field.Name)fmt.Printf("\tWhole tag value : %s\n", field.Tag)fmt.Printf("\tValue of 'mytag': %s\n", field.Tag.Get("mytag"))}
}
上面的程序会输出
Field: User.NameWhole tag value : mytag:"MyName"Value of 'mytag': MyName
Field: User.EmailWhole tag value : mytag:"MyEmail"Value of 'mytag': MyEmail
常用的结构体标签键
常用的结构体标签Key,指的是那些被一些常用的开源包声明使用的结构体标签键。在这里总结了一些,都是一些我们平时会用到的包,它们是:
json
: 由encoding/json
包使用,详见json.Marshal()
的使用方法和实现逻辑。xml
: 由encoding/xml
包使用,详见xml.Marshal()
。bson
: 由gobson
包,和mongo-go
包使用。protobuf
: 由github.com/golang/protobuf/proto
使用,在包文档中有详细说明。yaml
: 由gopkg.in/yaml.v2
包使用,详见yaml.Marshal()
。gorm
: 由gorm.io/gorm
包使用,示例可以在GORM的文档中找到。
当然这里列的就是最常用的几个库他们提供给我们使用的结构体标签,欢迎大伙踊跃留言,补充一些自己平时用过的库提供给开发者使用的结构体标签。
总结
这篇文章算是我们上一篇讲Go反射的一个实践方向的延伸介绍,如果你也想在自己的包里提供一些结构体标签键,让自己的包更易用些,除了看咱们这篇文章外,还可以去看看上面咱们介绍的几个类库,看它们的源码里是怎么应用的,现学现用!
相关文章
实战演示Go反射的使用方法和应用场景
- END -
扫码关注公众号「网管叨bi叨」
给网管个星标,第一时间吸我的知识
盘点一下结构体标签在Go中的应用相关推荐
- C语言中结构体标签的使用
C语言中结构体标签的使用 我们都知道,结构体标签就是结构体的名称,为结构体命名可以方便我们在后续继续使用该结构体. 如 struct student {char* name;int age; }str ...
- go语言结构体标签的意义
如加入json解析格式 如下代码: package mainimport ("encoding/json""fmt""reflect" )t ...
- golang常用库之mapstructure包 | 多json格式情况解析、GO json 如何转化为 map 和 struct、Go语言结构体标签(Struct Tag)
文章目录 golang常用库之mitchellh/mapstructure包 | go将map转换为struct 一.msgpack 二.背景 三.多json格式情况解析使用思路 四.mapstruc ...
- C语言小记:结构体及其在内存中的储存形式
C语言小记:结构体及其在内存中的储存形式 1.结构体 结构体的作用:自定义一个包含多种不同数据类型的变量. 语法: struct 结构体名称 {结构体成员1:结构体成员2:结构体成员3:... } 定 ...
- 33. 使用fread()/fwrite()往文件中写入结构体,从文件中读出结构体
1 //读写结构体 2 #include <stdio.h> 3 typedef struct student 4 { 5 int num; 6 char name[30]; 7 char ...
- matlab单元数组与结构体的区别,MATLAB中的结构体和单元数组
MATLAB中的结构体和单元数组 一.结构: x.real=10 x.imag=5 增加字段 x.scale=1 使用struct函数 s=struct('field1',values1,'field ...
- 在QT中结构体快速从二进制文件中读取数据
这可能是一个比较基础的问题,但由于刚开始学习c++,但是对我来说,结构体快速从二进制文件读取数据,给我解决了很大的问题,这里我把方法写出来,和有需要的人分享一下,高手看到了请多包涵. 我的二进制文件是 ...
- Linux中的两个经典宏定义:获取结构体成员地址,根据成员地址获得结构体地址;Linux中双向链表的经典实现。...
倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of 这两个宏应该不陌生.这两个宏最初是极客写出的,后来在Linux内核中被推广使用. 1. offse ...
- c语言定义学生结构体类型,C语言中结构体的三种定义方式
c语言中结构体的定义: struct 结构体名{ 成员列表: ..... }结构体变量: 7.1.1 结构体类型变量的定义 结构体类型变量的定义与其它类型的变量的定义是一样的,但由于结构体类型需要针对 ...
最新文章
- Hadoop源代码分析 - MapReduce(转载)
- FactoryMethod工厂方法模式升级成AbstractFactory抽象工厂模式
- 解决ifconfig命令未找到
- 计算机显卡敀主要性能参数,显卡性能看什么参数(新手必备的显卡性能知识全解)...
- jQuery EasyUI API 中文文档 - 数字框(NumberBox)
- 无边框对话框改变大小
- python链表怎么定义_python:链表定义以及实现
- python while循环和双重循环
- react-native技术调研:react-native是什么?
- 快逸报表传递中文参数乱码解决
- Android打字机动画,Android自定义View实现打字机效果
- 【2021年度总结】旧年的喜怒哀乐和新年的虎啸龙腾
- Python打印简单杨辉三角形
- 计算机专业教学总结,计算机教研组教学工作总结
- 一文说透企业风险管理的三大要素分别是什么
- Nginx之proxy_pass详解
- 0.《新概念51单片机C语言教程》(郭天祥)学习笔记
- C语言小游戏: 2048.c
- Epoch, Batch, Iteration 区别
- 【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...