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 能夠被 reflect 包獲取到,其實除了經過反射機制能獲取到 Tag 信息,對於其餘方式這些標記都是不可見的!
咱們先來看看官方 reflect 中 StructTag 部分,reflect - The Go Programming Language。
StructTag 是 string 基本類型的別名: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 的 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 選項。
Name string json:",omitempty"
,直接英文逗號打頭。Omitempty string json:"omitempty,omitempty"
,記住第一個字符串表示的是新變量名,而不是選項,因此重名就重名好了,不怕🤪。思考一下:- string json:"-,"
和- string json:",-"
有什麼區別🧐?
經常使用的一些 Struct Tag 官方有列舉,Well known struct tags · golang/go Wiki · GitHub。