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”
email合法邮箱校验binding:”email”
url合法的URLbinding:”url”
uri合法的URIbinding:”uri”
uuiduuid验证binding:”uuid”
datetime合法时间格式值校验binding:”datetime=2006-01-02″
jsonJSON数据验证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”
asciiAscii 字符验证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"`
}

标签