go结构体标签
结构体除了字段名和类型外,还有一个可选的标签(tag),标签是附属于字段的字符串,可以是文档或者其他标记
tag是结构体编译截断关联到成员的元信息字符串,在运行时候通过反射机制读取出来
结构体标签由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔,格式如下:
`key1:"value1" key2:"value2" key3:"value3"...` // 键值对用空格分隔
注意:冒号左右不能有空格,否则运行输出结果可能不对,所以,编写 Tag 时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误
key会指定反射的解析方式包含 :json(JSON标签)、 orm(Beego标签)、gorm(GORM标签)、bson(MongoDB标签)、form(表单标签)、binding(表单验证标签)
一、json标签:
1、首先看一个没有任何标签的结构体序列化为json的例子,如图:

序列化后的内容为:

从上图可以看出,序列化之后的json的key还是保持原来结构体的字段名,大小写都一样
2、给结构体字段添加标签,并设置不同规则,如图:

- 9行:将标签设置为json:name,表示序列化后将字段名转换为小写
- 10行:标签值有两个,第一个是字段名,第二个为将类型从int转换为string
- 11行:设置omitempty,如果结构体实例化时没指定此字段,则不显示
- 12行:标签值为-,表示此字段不参与序列化
- 19行:将实例化结构体时候的字段Weight注释

从上图看出,Name和Age都转换为了小写格式,并且Age的类型从int转为了string,Weight设置了omitempty,并且实例化结构体时候没有指定此字段,因此不显示,Height设置为”-“,默认就不参与序列化
3、将Weight的json标签对应的字段值取消,设置omitempty,实例化指定字段,如图:


从上图看出,如果标签不指定字段,实例化指定字段,序列化结果字段与原字段一样
| 标签选项 | 说明 |
| – | 字段不参与序列化 例:json:”-“ |
| omitempty | 字段零值或空值,序列化忽略该字段 例:json:”,omitempty”字段名省略使用结构体原字段名 |
| type | 重新指定字段类型 例: json:”age,string”,将age从int指定为string |
注:json标签可以理解为将传入的json数据绑定到对应的结构体字段中
二、gorm标签:
1、首先定义一个没有任何标签的结构体,通过此结构体创建数据,如图:

执行命令后可以看到表中结构如下:

从上图看出,gorm默认使用ID作为主键,并设置自增,使用结构体名复数作为表名,字段名作为表列名,遵循Snake Case命名风格,多个单词使用下划线分隔,字段类型也是默认的
2、给结构体添加标签,并设置对应表字段属性,重新创建表,如图:

执行后,看到创建的表结构如下:

从上图看出,在结构体标签中设置列名以及type后,对应的表结构就是设置之后的,comment为注释字段,可写可不写
注:如果不是通过gorm创建的表,那么结构体的字段名要么与表名对应,要么就要在gorm中指定表列名,否则会报错,使用gorm Migrator创建表时 ,不会创建被忽略的字段
字段标签:
| 标签名 | 说明 |
| column | 指定db列名 |
| type | 列数据类型,bool,int,uint,float等 |
| size | 列大小,例如:size:256 |
| primaryKey | 指定列为主键 |
| unique | 指定列为唯一 |
| default | 指定列的默认值 |
| precision | 指定列的精度 |
| scale | 指定列大小 |
| not null | 指定列为 NOT NULL |
| autoincrement | 指定列为自动增长 |
| embedded | 嵌套字段 |
| embeddedPrefix | 嵌入字段的列名前缀 |
| autoCreateTime | 创建时追踪当前时间,对于 int 字段,它会追踪秒级时间戳 |
| autoUpdateTime | 创建/更新时追踪当前时间,对于 int 字段,它会追踪秒级时间戳 |
| index | 根据参数创建索引,多个字段使用相同的名称则创建复合索引 |
| uniqueIndex | 与 index 相同,但创建的是唯一索引 |
| check | 创建检查约束,例如 check:age > 13,查看 约束 获取详情 |
| <- | 设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限 |
| -> | 设置字段读的权限,->:false 无读权限 |
| – | 忽略该字段,- 无读写权限 |
| comment | 迁移时为字段添加注释 |
关联标签:
| 标签名 | 说明 |
| foreignKey | 指定当前模型的列作为连接表的外键 |
| references | 指定引用表的列名,其将被映射为连接表外键 |
| polymorphic | 指定多态类型,比如模型名 |
| polymorphicValue | 指定多态值、默认表名 |
| many2many | 指定连接表表名 |
| joinForeignKey | 指定连接表的外键列名,其将被映射到当前表 |
| joinReferences | 指定连接表的外键列名,其将被映射到引用表 |
| constraint | 关系约束,例如:OnUpdate、OnDelete |
三、form标签:
Gin中提供了模型绑定,将表单数据和模型进行绑定,方便参数校验和使用
注意:字段名首字母一定要大写,否则获取不到
1、下面例子表示将gin的url获取的参数将结构体模型绑定,如图:

- 第15行:定义结构体user,字段名字必须要大写,通过form标签指定字段名,字段名和form之间不可以有空格
- 第19行:通过c.Bind()方法将gin获取的参数绑定到结构体模型中
- 第23行:在c.JSON中获取字段的值
通过postman调用接口,如果上面没有写标签form,那么postman中的字段必须要和结构体字段一致,也就是字段首字母要大写,加了标签form后就可以小写了

注意:除了Bind()方法,还有ShouldBind()方法、
如果是通过url获取参数,可用gin的GET方法,如果是提交的表单是数据,需要用POST方法:

通过postman请求如下:

注意:在通过接口请求的时候,字段名要用小写形式就行,比如上面的username,因为已经通过form指定了,将小写的username绑定到大写的Username字段上
四、binding标签:
gin对于数据校验使用的是validator:v10包,该包提供了多种数据校验方法,通过binding:””标签实现校验
type Userpass struct {
Username string `json:"username" binding:"required,max=30"`
Password string `json:"password" binding:"required,max=30"`
IPAddress string `json:"ipaddress" binding:"required,ip"`
}
注:binding标签一般用于字段校验
符号说明:
| 符号 | 说明 |
| , | 分隔多个标签选项,逗号之间不能有空格 |
| – | 该字段不做校验 |
| | | 使用多个选项,满足其中一个即可 |
必须校验:
| 选项 | 说明 | 示例 |
| required | 表示该字段值必输设置,且不能为默认值 | binding:”required” |
| omitempty | 如果字段未设置,则忽略它 | binding:”omitempty” |
字符串校验:
| 选项 | 说明 | 示例 |
| contains | 参数值包含设置子串 | binding:”contains=abc”是否包含abc字符串 |
| excludes | 参数值不包含设置子串 | binding:”excludes=abc”是否不包含abc字符串 |
| startswith | 字符串前缀 | binding:”startswith=abc”是否以abc开头 |
| endswith | 字符串前缀 | binding:”endswith=abc”是否以abc结尾 |
范围校验:
| 选项 | 说明 | 示例 |
| len | 参数值等于给定值 | binding:”len=3″ |
| ne | 不等于 | binding:”ne=3″ |
| max | 最大值,小于等于参数值 | binding:”max=3″ |
| min | 最小值,大于等于参数值 | binding:”min=3″ |
| lte | 参数值小于等于给定值 | binding:”lte=3″ |
| gte | 参数值大于等于给定值 | binding:”gte=3″ |
| lt | 参数值小于给定值 | binding:”lt=3″ |
| gt | 参数值大于给定值 | binding:”gt=3″ |
| oneof | 参数值只能是枚举值中的一个,值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围 | binding:”oneof=red green” |
字段校验:
| 选项 | 说明 |
| eqcsfield | 跨不同结构体字段相等,比如struct1 field1 是否等于struct2 field2 |
| necsfield | 跨不同结构体字段不相等 |
| eqfield | 同一结构体字段相等验证,例如:输入两次密码 |
| nefield | 同一结构体字段不相等验证 |
| gtefield | 大于等于同一结构体字段 |
| ltefield | 小于等于同一结构体字段 |
// 不同结构体校验
type hello struct {
a string `validate:eqcsfield=b.c`
b struct {
c string
}
}
// 同一结构体字段相同校验
type a struct {
b string `validate:"lte=4"`
c string `validate:"min=10"`
d string `validate:"eqfield=c"`
}
// 同一结构体字段不相等
type User struct {
Name string `validate:"lte=4"`
Age int `validate:"min=20"`
Password string `validate:"min=10,nefield=Name"`
}
其他校验:
| 选项 | 说明 | 示例 |
| ip | 合法IP地址校验 | binding:”ip” |
| 合法邮箱校验 | binding:”email” | |
| url | 合法的URL | binding:”url” |
| uri | 合法的URI | binding:”uri” |
| uuid | uuid验证 | binding:”uuid” |
| datetime | 合法时间格式值校验 | binding:”datetime=2006-01-02″ |
| json | JSON数据验证 | validate:”json” |
| numeric | 数值验证 正则:^[-+]?[0-9]+(?:\\.[0-9]+)?$ | validate:”numeric” |
| number | 整数验证 正则:^[0-9]+$ | validate:”number” |
| alpha | 字母字符串验证 正则:^[a-zA-Z]+$ | validate:”alpha” |
| alphanum | 字母数字字符串验证 正则:^[a-zA-Z0-9]+$ | validate:”alphanum” |
| ascii | Ascii 字符验证 | validate:”ascii” |
五、ini标签
ini 是 Windows 上常用的配置文件格式, go-ini是 Go 语言中用于操作 ini 文件的第三方库
若使用ini格式配置,需要将配置文件字段映射到结构体变量,如果键名与字段名不相同,那么需要在结构标签中指定对应的键名。标准库encoding/json、encoding/xml解析时可以将键名直接对应到字段名,而go-ini库不可以,所以需要在结构体标签指定对应键名。
## 配置文件 cnf.ini
user_name = ares
age = 20
// 配置文件映射 结构体
type Config struct {
UserName string `ini:"user_name"` // ini标签指定下键名
Age string `ini:"age"`
}


