Tags in Golang

來源:互聯網
上載者:User

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

在學習過程中,看到類似上面的代碼,一下子懵了個逼。。。大概一查,這是 Golang 中的 Tags 文法,官方解釋是這樣的:

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)。

舉例子

舉一個 API 的例子 ,擷取使用者ID為1的使用者資訊:GET /v1/user/1。簡單的做法是在擷取到資料庫 user 表的一條記錄後,以 JSON 格式返回。

type User struct {    Id int  Name string  Age int8}

如果不做任何處理,那麼此時返回的資料應該是如下:

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

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

我們為結構體屬性加上標記:

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 包使用和處理。

如果有多個 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。

參考連結

  • json - The Go Programming Language
  • reflect - The Go Programming Language
  • Struct types - The Go Programming Language Specification
  • String literals - The Go Programming Language Specification
  • reflection - What are the use(s) for tags in Go? - Stack Overflow
  • Tags in Golang – golangspec – Medium
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.