原文链接:

前言

asongGo

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

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

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

json:"lon,omitempty"jsonlonlatlonlatomitempty

看到这里,有一些朋友可能会好奇,这个你是怎么知道这样使用的呢?我可以随便写标签吗?

接下来我们就一点点来揭秘,开车!!!

什么是标签

Gojson/xmlormencoding/json
`key1:"value1" key2:"value2" key3:"value3"...`  // 键值对用空格分隔

结构体标签可以有多个键值对,键与值要用冒号分隔,值要使用双引号括起来,多个键值对之间要使用一个空格分隔,千万不要使用逗号!!!

encoding/json
`json:"lon,omitempty"`
gorm
`gorm:"column:id;primaryKey"

具体使用什么符号分隔需要大家要看各自库的文档获取。

结构体标签是在编译阶段就和成员进行关联的,以字符串的形式进行关联,在运行阶段可以通过反射读取出来。

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 pairbad syntax for struct tag value
go vetCI

标签使用场景

Gostruct tag
TagDocumentation
jsonyamlgormvalidatemapstructureprotobufginvalidatevalidate

具体这些库中是怎么使用的,大家可以看官方文档介绍,写的都很详细,具体场景具体使用哈!!!

自定义结构体标签

现在我们可以回答开头的一个问题了,结构体标签是可以随意写的,只要符合语法规则,任意写都可以的,但是一些库没有支持该标签的情况下,随意写的标签是没有任何意义的,如果想要我们的标签变得有意义,就需要我们提供解析方法。可以通过反射的方式获取标签,所以我们就来看一个例子,如何使用反射获取到自定义的结构体标签。

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
TypeOfStructFieldTag
// 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
}
TagGetLoopup
func (tag StructTag) Get(key string) string
func (tag StructTag) Lookup(key string) (value string, ok bool)
GetLookupLookupkeyGet

总结

Govalidaetag
asong

欢迎关注公众号:Golang梦工厂