go中Tag的理解與使用

水墨先生發表於2021-10-07

這篇文章主要想分享一下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 協議》,轉載必須註明作者和本文連結

相關文章