关于golang:Go语言中结构体打Tag是什么意思

25次阅读

共计 3742 个字符,预计需要花费 10 分钟才能阅读完成。

原文链接:Go 语言中构造体打 Tag 是什么意思?

前言

哈喽,大家好,我是 asong。明天想与大家分享Go 语言中构造体标签是怎么应用的,以及怎么定制本人的构造体标签解析。

大多数初学者在看公司的我的项目代码时,看到的一些构造体定义会是这样的:

type Location struct {
    Longitude float32 `json:"lon,omitempty"`
    Latitude  float32 `json:"lat,omitempty"`
}

字段前面会有一个标签,这个标签有什么用呢?

下面的例子中,标签 json:"lon,omitempty" 代表的意思是构造体字段的值编码为 json 对象时,每一个导出字段变成该对象的一个成员,这个成员的名字为 lon 或者 lat,并且当字段是空值时,不导出该字段;总结就是lonlat 是重命名成员的名字,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…

jsonyamlgormvalidatemapstructureprotobuf 这几个库的构造体标签是很罕用的,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是一个内置类型,提供了 GetLoopup 两种办法来解析标签中的值并返回指定键的值:

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 梦工厂

正文完
 0