go中Tag的理解与使用

这篇文章主要想分享一下 Go 的 struct 声明允许字段附带 Tag 来对字段做一些标记究竟有什么作用,是用来干嘛的,开始步入正题。

struct 中字段的 Tag 不仅仅是一个字符串那么简单,因为其主要用于反射场景,reflect 包中提供了操作 Tag 的方法,所以 Tag 写法也要遵循一定的规则。

  • Tag 规则
    1. Tag 本身是一个字符串,但字符串中却是,以空格分隔的 key:value 对 。
    2. key: 必须是非空字符串,字符串不能包含控制字符、空格、引号、冒号。
    3. value: 以双引号标记的字符串
    4. 注意:冒号前后不能有空格
    5. 如下代码所示,如此写没有实际意义,仅用于说明 Tag 规则是咋样的,ServerName 字段的 Tag 包含两个 key-value 对。ServerIP 字段的 Tag 只包含一个 key-value 对。:
      type Server struct {
      ServerName string `key1: "value1" key11:"value11"`
      ServerIP string `key2: "value2"`
      }

必须要理解的是 Tag 是 Struct 的一部分,前面说过 Tag 只有在反射场景中才有用,而反射包中提供了操作 Tag 的方法,在说方法前,有必要先了解一下 Go 是如何管理 struct 字段的。

  • 以下是 reflect 包中的类型声明,省略了部分与无关的字段:
    type StructField struct {
       Name string
       Type Type
       Tag StructTag
    }
    type StructTag string
  • 如上可见,描述一个结构体成员的结构中包含了 StructTag, 而其本身是一个 string, 也就是说 Tag 其实是结构体字段的一个组成部分。

下面说一下如何获取 Tag
StructTag 提供了 Get (key string) string 方法来获取 Tag,示例如下:

func main() {
    s := Server{}
    st := reflect.TypeOf(s)
    field1 := st.Field(0)
    fmt.Printf("key1:%v\n",field1.Tag.Get("key1"))
    fmt.Printf("key11:%v\n",field1.Tag.Get("key11"))
    filed2 := st.Field(1)
    fmt.Printf("key2:%v\n",filed2.Tag.Get("key2"))
}
//程序输出如下:
key1:value1
key11:value11
key2:value2

最后讲一下 Tag 存在的意义与常见用法

  • 注意:本文示例中 tag 没有任何实际意义,只是为了阐述 tag 的定义与操作方法而已。
  • 在使用反射可以动态的给结构体成员赋值,正是因为有 tag,在赋值前可以使用 tag 来决定赋值的动作。比如,官方的 encoding/json 包,可以将一个 JSON 数据 Unmarshal 进一个结构体,此过程中就使用了 Tag, 该包定义一些规则,只要参考该规则设置 tag 就可以将不同的 JSON 数据转换成结构体。
  • 基于 struct 的 tag 特性,有了诸如 json、orm 等等的应用。理解这个可以定义另一种 tag 规则,来处理特有的数据。

Tag 的内容我所理解和了解的只有这么多了,还有更多玩法的欢迎留言评论告知

本作品采用《CC 协议》,转载必须注明作者和本文链接