原文链接:Go 语言中构造体打 Tag 是什么意思?
前言
哈喽,大家好,我是 asong
。明天想与大家分享Go
语言中构造体标签是怎么应用的,以及怎么定制本人的构造体标签解析。
大多数初学者在看公司的我的项目代码时,看到的一些构造体定义会是这样的:
type Location struct {
Longitude float32 `json:"lon,omitempty"`
Latitude float32 `json:"lat,omitempty"`
}
字段前面会有一个标签,这个标签有什么用呢?
下面的例子中,标签 json:"lon,omitempty"
代表的意思是构造体字段的值编码为 json
对象时,每一个导出字段变成该对象的一个成员,这个成员的名字为 lon
或者 lat
,并且当字段是空值时,不导出该字段;总结就是lon
、lat
是重命名成员的名字,omitempty
用来决定成员是否导出。
看到这里,有一些敌人可能会好奇,这个你是怎么晓得这样应用的呢?我能够轻易写标签吗?
接下来咱们就一点点来揭秘,开车!!!
什么是标签
Go
语言提供了可通过反射发现的的构造体标签,这些在规范库 json/xml
中失去了宽泛的应用,orm
框架也反对了构造体标签,下面那个例子的应用就是因为 encoding/json
反对了构造体标签,不过他有本人的标签规定;然而他们都有一个总体规定,这个规定是不能更改的,具体格局如下:
`key1:"value1" key2:"value2" key3:"value3"...` // 键值对用空格分隔
构造体标签能够有多个键值对,键与值要用冒号分隔,值要应用双引号括起来,多个键值对之间要应用一个空格分隔,千万不要应用逗号!!!
如果咱们想要在一个值中传递多个信息怎么办?不同库中实现的是不一样的,在 encoding/json
中,多值应用逗号分隔:
`json:"lon,omitempty"`
在 gorm
中,多值应用分号分隔:
`gorm:"column:id;primaryKey"
具体应用什么符号分隔须要大家要看各自库的文档获取。
构造体标签是在编译阶段就和成员进行关联的,以字符串的模式进行关联,在运行阶段能够通过反射读取进去。
当初大家曾经晓得什么是构造体标签了,规定还是很标准的,然而很容易出错,因为 Go 语言在编译阶段并不会对其格局做非法键值对的查看,这样咱们不小心写错了,就很难被发现,不过咱们有 go vet
工具做查看,具体应用来看一个例子:
type User struct {
Name string `abc def ghk`
Age uint16 `123: 232`
}
func main() {}
而后执行go vet main.go
,得出执行后果:
# command-line-arguments
go_vet_tag/main.go:4:2: struct field tag `abc def ghk` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
go_vet_tag/main.go:5:2: struct field tag `123: 232` not compatible with reflect.StructTag.Get: bad syntax for struct tag value
bad syntax for struct tag pair
通知咱们键值对语法错误,bad syntax for struct tag value
值语法错误。
所以在咱们我的项目中引入 go vet
作为 CI
查看是很有必要的。
标签应用场景
Go
官网曾经帮忙整顿了哪些库曾经反对了struct tag
:https://github.com/golang/go/…。
Tag | Documentation |
---|---|
xml | https://godoc.org/encoding/xml |
json | https://godoc.org/encoding/json |
asn1 | https://godoc.org/encoding/asn1 |
reform | https://godoc.org/gopkg.in/re… |
dynamodb | https://docs.aws.amazon.com/s… |
bigquery | https://godoc.org/cloud.googl… |
datastore | https://godoc.org/cloud.googl… |
spanner | https://godoc.org/cloud.googl… |
bson | https://godoc.org/labix.org/v…, https://godoc.org/go.mongodb…. |
gorm | https://godoc.org/github.com/… |
yaml | https://godoc.org/gopkg.in/ya… |
toml | https://godoc.org/github.com/… |
validate | https://github.com/go-playgro… |
mapstructure | https://godoc.org/github.com/… |
parser | https://godoc.org/github.com/… |
protobuf | https://github.com/golang/pro… |
db | https://github.com/jmoiron/sqlx |
url | https://github.com/google/go-… |
feature | https://github.com/nikolaydub… |
像 json
、yaml
、gorm
、validate
、mapstructure
、protobuf
这几个库的构造体标签是很罕用的,gin
框架就集成了 validate
库用来做参数校验,不便了许多,之前写了一篇对于 validate
的文章:boss: 这小子还不会应用 validator 库进行数据校验,开了~~~,能够关注一下。
具体这些库中是怎么应用的,大家能够看官网文档介绍,写的都很具体,具体场景具体应用哈!!!
自定义构造体标签
当初咱们能够答复结尾的一个问题了,构造体标签是能够随便写的,只有合乎语法规定,任意写都能够的,然而一些库没有反对该标签的状况下,随便写的标签是没有任何意义的,如果想要咱们的标签变得有意义,就须要咱们提供解析办法。能够通过反射的形式获取标签,所以咱们就来看一个例子,如何应用反射获取到自定义的构造体标签。
type User struct {
Name string `asong:"Username"`
Age uint16 `asong:"age"`
Password string `asong:"min=6,max=10"`
}
func getTag(u User) {t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {field := t.Field(i)
tag := field.Tag.Get("asong")
fmt.Println("get tag is", tag)
}
}
func main() {
u := User{
Name: "asong",
Age: 5,
Password: "123456",
}
getTag(u)
}
运行后果如下:
get tag is Username
get tag is age
get tag is min=6,max=10
这里咱们应用 TypeOf
办法获取的构造体类型,而后去遍历字段,每个字段 StructField
都有成员变量Tag
:
// A StructField describes a single field in a struct.
type StructField struct {
Name string
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
Tag
是一个内置类型,提供了 Get
、Loopup
两种办法来解析标签中的值并返回指定键的值:
func (tag StructTag) Get(key string) string
func (tag StructTag) Lookup(key string) (value string, ok bool)
Get
外部也是调用的 Lookup
办法。区别在于 Lookup
会通过返回值告知给定 key
是否存在与标签中,Get
办法齐全疏忽了这个判断。
总结
本文次要介绍一下 Go
语言中的构造体标签是什么,以及如何应用反射获取到解构造体标签,在日常开发中咱们更多的是应用一些库提供好的标签,很少本人开发应用,不过大家有趣味的话能够读一下 validae
的源码,看看他是如何解析构造体中的tag
,也能够本人入手实现一个校验库,当作练手我的项目。
文中代码已上传github
:https://github.com/asong2020/…
好啦,本文到这里就完结了,我是asong
,咱们下期见。
欢送关注公众号:Golang 梦工厂