前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >盘点一下结构体标签在Go中的应用

盘点一下结构体标签在Go中的应用

作者头像
KevinYan
发布2021-11-10 11:06:41
7760
发布2021-11-10 11:06:41
举报
文章被收录于专栏:网管叨bi叨网管叨bi叨

掌握了Go语言的朋友们应该都知道,在Go的结构体类型声明里面,字段声明后可以跟一个可选的字符串标签。

代码语言:javascript
复制
type User struct {
    Name string `json:"name"`
}

上面是一个标准的例子,Name字段声明中指定了标签json:"name" xml:"name" ,这个标签值看着有点类似Java程序里给类属性加的注解。

那么这些结构体标签有什么用途呢,我们随便写管用吗?我们平时工作中常用的结构体标签有哪些呢?我们能不能自己定义结构体标签?今天就带大家掰扯清楚这些问题!

结构体标签

Go语言允许我们通过结构体字段标签给一个字段附加可以被反射获取的”元信息“,正好我们上篇文章实战演示Go反射的使用方法和应用场景中讲了Go语言反射使用方法相关的内容,对反射不清楚的可以先去再复习一下。

通常情况下,结构体标签被用于提供结构体字段如何被编码为或者解码自另外一种格式的转换信息(或者是以何种形式被保存至/获取自数据库)。不过,你也可以用它存储任何你想要设置的”元信息“,供其他包或者自己使用。

使用规范

结构体标签在使用上通常是遵守下面三个规范。

结构体标签字符串的值是一个由空格分隔的 key:"value" 对列表,例如:

代码语言:javascript
复制
type User struct {
    Name string `json:"name" xml:"name"`
}

键,通常表示后面跟的“值”是被哪个包使用的,例如json这个键会被encoding/json包处理使用。如果要在“键”对应的“值”中传递多个信息,通常通过用逗号(',')分隔来指定,例如

代码语言:javascript
复制
Name string `json:"name,omitempty"`

按照惯例,如果一个字段的结构体标签里某个键的“值”被设置成了的破折号 ('-'),那么就意味着告诉处理该结构体标签键值的进程排除该字段。例如,把一个字段的标签设置成下面这样

代码语言:javascript
复制
Name string `json:"-"`

就以为进行JSON编码/解码时忽略Name这个字段。

怎么获取到结构体标签

从一开始我们就说结构体标签是给反射准备的,那么怎么在Go程序里用反射获得到字段的结构体标签呢?看了我们上一篇文章的同学,应该会知道,结构体字段类型相关的信息,在反射的世界里使用reflect.StructFiled这个类型表示的。

代码语言:javascript
复制
type StructField struct {
 Name string
 Type      Type      // field type
 Tag       StructTag // field tag string
  ......
}

如上所示,其中包含的Tag字段即代表了字段声明中的结构体标签信息。让我们通过自定义结构体标签的例子来演示一下怎么使用它在反射里读取到标签里的信息。

用反射获取到自定义的结构体标签

使用反射reflect包访问结构体字段的标签值,我们需要先获取到结构体的类型信息Type,然后使用Type.Field(i int)Type.FieldByName(name string),方法查询字段信息,这两个方法都会返回一个StructField类型的值,上面我们也说了它在反射的世界里用于描述一个结构体字段;而StructField.Tag 是一个StructTag 类型的值,它描述了字段的标签。

上面我们谈到了结构体标签的使用规范,如果遵循规范给字段设置了标签后,就可以使用StructTagGet方法解析标签的值并返回你指定的键的“值”。

代码语言:javascript
复制
func (tag StructTag) Get(key string) string

为了方便判断一个给定的key是否存在与标签中,StructTag还提供了一个Lookup方法

代码语言:javascript
复制
func (tag StructTag) Lookup(key string) (value string, ok bool)

Get方法不同的是,Lookup会通过返回的ok值告知给定key是否存在与标签中。

下面通过一个例子,演示下获取我们自定义标签的过程。

代码语言:javascript
复制
package main

import (
 "fmt"
 "reflect"
)

type User struct {
 Name  string `mytag:"MyName"`
 Email string `mytag:"MyEmail"`
}



func main() {
 u := User{"Bob", "bob@mycompany.com"}
 t := reflect.TypeOf(u)

 for i := 0; i < t.NumField(); i++ {
  field := t.Field(i)
  fmt.Printf("Field: User.%s\n", field.Name)
  fmt.Printf("\tWhole tag value : %s\n", field.Tag)
  fmt.Printf("\tValue of 'mytag': %s\n", field.Tag.Get("mytag"))
 }
}

上面的程序会输出

代码语言:javascript
复制
Field: User.Name
        Whole tag value : mytag:"MyName"
        Value of 'mytag': MyName
Field: User.Email
        Whole tag value : mytag:"MyEmail"
        Value of 'mytag': MyEmail

常用的结构体标签键

常用的结构体标签Key,指的是那些被一些常用的开源包声明使用的结构体标签键。在这里总结了一些,都是一些我们平时会用到的包,它们是:

  • json: 由encoding/json 包使用,详见json.Marshal()的使用方法和实现逻辑。
  • xml : 由encoding/xml包使用,详见xml.Marshal()
  • bson: 由gobson包,和mongo-go包使用。
  • protobuf: 由github.com/golang/protobuf/proto 使用,在包文档中有详细说明。
  • yaml: 由gopkg.in/yaml.v2 包使用,详见yaml.Marshal()
  • gorm: 由gorm.io/gorm包使用,示例可以在GORM的文档中找到。

当然这里列的就是最常用的几个库他们提供给我们使用的结构体标签,欢迎大伙踊跃留言,补充一些自己平时用过的库提供给开发者使用的结构体标签

总结

这篇文章算是我们上一篇讲Go反射的一个实践方向的延伸介绍,如果你也想在自己的包里提供一些结构体标签键,让自己的包更易用些,除了看咱们这篇文章外,还可以去看看上面咱们介绍的几个类库,看它们的源码里是怎么应用的,现学现用!

相关文章

- END -

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网管叨bi叨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结构体标签
    • 使用规范
      • 怎么获取到结构体标签
        • 用反射获取到自定义的结构体标签
        • 常用的结构体标签键
        • 总结
          • 相关文章
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档