Tags in Golang

圖片描述

type People struct {
    Name string `json:"name"`
    Age  int8   `json:"age"`
}

在學習過程當中,看到相似上面的代碼,一會兒懵了個逼😳。。。大概一查,這是 Golang 中的 Tags 語法,官方解釋是這樣的:git

A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface but are otherwise ignored.

官方的解釋不夠接地氣,像我這樣的初學者看了等因而沒看的,咱們加點實際場景進去就能明白這到底能幹嘛。
因爲 Golang 中對字段的標記能夠在 反射 時獲取到,因此一般是用來在將 struct 編碼轉換的過程當中提供一些轉換規則的信息,好比👇下面例子中提到的 JSON 轉換。固然你也能夠用它來存儲你想要的任何其餘元信息(Meta-information)。github

舉例子

舉一個 API 的例子 🌰,獲取用戶ID爲1的用戶信息:GET /v1/user/1。簡單的作法是在獲取到數據庫 user 表的一條記錄後,以 JSON 格式返回。golang

type User struct {
    Id int
  Name string
  Age int8
}

若是不作任何處理,那麼此時返回的數據應該是以下:數據庫

{"Id":1,"Name":"X.FLY","Age":24}

咦,爲啥都給我返回駝峯型的屬性名啊?誰讓你聲明 User 結構體的時候屬性名就是這樣呢。
那麼把結構體屬性名改爲小寫吧。🚫 不行🚫,由於這樣這些屬性就都變成了私有屬性了,別忘了 Golang 裏面可沒有 public / private / protected 這些關鍵詞,全靠首字母大小寫來區分好不!
那咋辦?用 Tag 啊 😂json

咱們爲結構體屬性加上標記:c#

type User struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
    Age  int8
}

故意不給 age 加標記以便看區別,JSON 格式輸出以下:函數

{"id":1,"name":"X.FLY","Age":24}

這就是 Tag 的神奇之處,不會污染到主體,也不須要在每次輸出 JSON 數據的時候人工處理(好吧,移除 public 等關鍵詞是須要付出代價的😅)。學習

使用方法

Tag 能夠是任何字符串,下面將的是常見形式,別想岔了🤭

通常來說,Tag 都是以 key:"value" 這種鍵值對的形式,若是有多個鍵值對,則以空格分隔。編碼

type User struct {
    Name string `json:"name" xml:"name"`
}

key 通常指的是要使用的包名,好比這裏的 json 表示這個 Name 字段會被 encoding/json 包使用和處理。spa

若是有多個 value 信息要傳入,那麼一般使用英文逗號 , 進行分隔。

type User struct {
    Name string `json:"name,omitempty" xml:"name"`
}

omitempty 代表若是這個字段的值在編解碼時爲空(Defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string)那麼就忽略這個字段。還有一個經常使用的是 -,它表示直接忽略這個字段。

理解 Tag

前面說到 Tag 能夠被 reflect 包獲取到,其實除了經過反射機制能獲取到 Tag 信息,對於其餘方式這些標記都是不可見的!
咱們先來看看官方 reflect 中 StructTag 部分,reflect - The Go Programming Language

StructTagstring 基本類型的別名:type StructTag string,約定俗成的規則是以 key:"value" 這樣的鍵值對。(若是我不按照這種 約定 來作呢?固然也能夠,可是這樣作會致使 StructTag.Get() 方法解析不了你那脫俗的標記,那麼你就只能本身實現本身的解析邏輯了,總之你高興就好😏)

func (tag StructTag) Get(key string) string

Get() 函數用於獲取指定 key 的 value,好比有一個標記是 mytag:"X.FLY",那麼 Get("mytag") => X.FLY

func (tag StructTag) Lookup(key string) (value string, ok bool)

Lookup() 函數是在 Golang 1.7 以後加的,用來判斷是否存在指定的 key。

使用例子能夠在 The Go Playground 上運行嘗試,這裏就對反射很少作展開了。

JSON’s Tag

這裏着重舉出 JSON 的 Struct Tag(1. JSON 輸出很常見; 2. 能夠以此類推其餘如 XML’s Tag)。
我想知道 JSON 的 tag 有哪些,去哪找?去官網 JSON.Marshal 函數文檔中找。

The encoding of each struct field can be customized by the format string stored under the "json" key in the struct field's tag. The format string gives the name of the field, possibly followed by a comma-separated list of options. The name may be empty in order to specify options without overriding the default field name.
咱們會發現,在 JSON 編碼過程當中會去獲取每個 Struct field 的標記,從中拿取 key 爲 json 的值,而後進行相應處理。

注意解析規則:value 的第一個字符串必定表示覆蓋後的新字段名,後面若是有解析選項,則以英文逗號分隔。

好比 Name string json:"name,omitempty",第一個字符串 name 表示在編碼後 Name 屬性名就變成了 name。而後緊跟逗號分隔符,接着是 omitempty 選項。

  1. 若是我不想覆蓋,只想加選項怎麼辦?Name string json:",omitempty",直接英文逗號打頭。
  2. 極端一點,若是個人字段名就叫 Omitempty 呢?Omitempty string json:"omitempty,omitempty",記住第一個字符串表示的是新變量名,而不是選項,因此重名就重名好了,不怕🤪。
思考一下: - string json:"-,"- string json:",-" 有什麼區別🧐?
  1. omitempty:若是字段的值爲空(Defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string),那麼在編碼過程當中就忽略掉這個字段。
  2. -:二話不說直接忽略該字段。
  3. string:將字段值在編碼過程當中轉換成 JSON 中的字符串類型,只有當字段類型是 string, floating point, integer, or boolean 的狀況下才會轉換。

其餘 Tag

經常使用的一些 Struct Tag 官方有列舉,Well known struct tags · golang/go Wiki · GitHub

參考連接

相關文章
相關標籤/搜索