Go語(yǔ)言struct要使用?tags的原因解析
在 Go 語(yǔ)言中,struct 是一種常見(jiàn)的數(shù)據(jù)類(lèi)型,它可以用來(lái)表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。在 struct 中,我們可以定義多個(gè)字段,每個(gè)字段可以有不同的類(lèi)型和名稱(chēng)。
除了這些基本信息之外,Go 還提供了 struct tags,它可以用來(lái)指定 struct 中每個(gè)字段的元信息。
在本文中,我們將探討為什么 Go 語(yǔ)言中需要使用 struct tags,以及 struct tags 的使用場(chǎng)景和優(yōu)勢(shì)。
struct tags 的使用
struct tags 使用還是很廣泛的,特別是在 json 序列化,或者是數(shù)據(jù)庫(kù) ORM 映射方面。
在定義上,它以 key:value
的形式出現(xiàn),跟在 struct 字段后面,除此之外,還有以下幾點(diǎn)需要注意:
使用反引號(hào)
在聲明 struct tag 時(shí),使用反引號(hào) `
包圍 tag 的值,可以防止轉(zhuǎn)義字符的影響,使 tag 更容易讀取和理解。例如:
type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Email string `json:"email" db:"email"` }
避免使用空格
在 struct tag 中,應(yīng)該避免使用空格,特別是在 tag 名稱(chēng)和 tag 值之間。使用空格可能會(huì)導(dǎo)致編碼或解碼錯(cuò)誤,并使代碼更難以維護(hù)。例如:
// 不規(guī)范的寫(xiě)法 type User struct { ID int `json: "id" db: "id"` Name string `json: "name" db: "name"` Email string `json: "email" db: "email"` } // 規(guī)范的寫(xiě)法 type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Email string `json:"email" db:"email"` }
避免重復(fù)
在 struct 中,應(yīng)該避免重復(fù)使用同一個(gè) tag 名稱(chēng)。如果重復(fù)使用同一個(gè) tag 名稱(chēng),編譯器可能會(huì)無(wú)法識(shí)別 tag,從而導(dǎo)致編碼或解碼錯(cuò)誤。例如:
// 不規(guī)范的寫(xiě)法 type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Email string `json:"email" db:"name"` } // 規(guī)范的寫(xiě)法 type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Email string `json:"email" db:"email"` }
使用標(biāo)準(zhǔn)化的 tag 名稱(chēng)
為了使 struct tag 更加標(biāo)準(zhǔn)化和易于維護(hù),應(yīng)該使用一些標(biāo)準(zhǔn)化的 tag 名稱(chēng)。
例如,對(duì)于序列化和反序列化,可以使用 json
、xml
、yaml
等;對(duì)于數(shù)據(jù)庫(kù)操作,可以使用 db
。
type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Password string `json:"-" db:"password"` // 忽略該字段 Email string `json:"email" db:"email"` }
其中,Password
字段后面的 -
表示忽略該字段,也就是說(shuō)該字段不會(huì)被序列化或反序列化。
多個(gè) tag 值
如果一個(gè)字段需要指定多個(gè) tag 值,可以使用 ,
將多個(gè) tag 值分隔開(kāi)。例如:
type User struct { ID int `json:"id" db:"id"` Name string `json:"name" db:"name"` Email string `json:"email,omitempty" db:"email,omitempty"` }
其中 omitempty
表示如果該字段值為空,則不序列化該字段。
struct tags 的原理
Go 的反射庫(kù)提供了一些方法,可以讓我們?cè)诔绦蜻\(yùn)行時(shí)獲取和解析結(jié)構(gòu)體標(biāo)簽。
介紹這些方法之前,先來(lái)看看 reflect.StructField
,它是描述結(jié)構(gòu)體字段的數(shù)據(jù)類(lèi)型。定義如下:
type StructField struct { Name string // 字段名 Type Type // 字段類(lèi)型 Tag StructTag // 字段標(biāo)簽 }
結(jié)構(gòu)體中還有一些其他字段,被我省略了,只保留了和本文相關(guān)的。
在結(jié)構(gòu)體的反射中,我們經(jīng)常使用 reflect.TypeOf
獲取類(lèi)型信息,然后使用 Type.Field
或 Type.FieldByName()
獲取結(jié)構(gòu)體字段的 reflect.StructField
,然后根據(jù) StructField
中的信息做進(jìn)一步處理。
例如,可以通過(guò) StructField.Tag.Get
方法獲取結(jié)構(gòu)體字段的標(biāo)簽值。
下面看一段代碼:
package main import ( "fmt" "reflect" ) type User struct { Name string `json:"name"` Age int `json:"age"` } type Manager struct { Title string `json:"title"` User } func main() { m := Manager{Title: "Manager", User: User{Name: "Alice", Age: 25}} mt := reflect.TypeOf(m) // 獲取 User 字段的 reflect.StructField userField, _ := mt.FieldByName("User") fmt.Println("Field 'User' exists:", userField.Name, userField.Type) // 獲取 User.Name 字段的 reflect.StructField nameField, _ := userField.Type.FieldByName("Name") tag := nameField.Tag.Get("json") fmt.Println("User.Name tag:", tag) }
運(yùn)行以上代碼,輸出結(jié)果如下:
Field 'User' exists: User {string int}
User.Name tag: "name"
struct tags 的優(yōu)勢(shì)
使用 struct tag 的主要優(yōu)勢(shì)之一是可以在運(yùn)行時(shí)通過(guò)反射來(lái)訪問(wèn)和操作 struct 中的字段。
比如在 Go Web 開(kāi)發(fā)中,常常需要將 HTTP 請(qǐng)求中的參數(shù)綁定到一個(gè) struct 中。這時(shí),我們可以使用 struct tag 指定每個(gè)字段對(duì)應(yīng)的參數(shù)名稱(chēng)、驗(yàn)證規(guī)則等信息。在接收到 HTTP 請(qǐng)求時(shí),就可以使用反射機(jī)制讀取這些信息,并根據(jù)信息來(lái)驗(yàn)證參數(shù)是否合法。
另外,在將 struct 序列化為 JSON 或者其他格式時(shí),我們也可以使用 struct tag 來(lái)指定每個(gè)字段在序列化時(shí)的名稱(chēng)和規(guī)則。
此外,使用 struct tag 還可以提高代碼的可讀性和可維護(hù)性。在一個(gè)大型的項(xiàng)目中,struct 中的字段通常會(huì)包含很多不同的元信息,比如數(shù)據(jù)庫(kù)中的表名、字段名、索引、驗(yàn)證規(guī)則等等。
如果沒(méi)有 struct tag,我們可能需要將這些元信息放在注釋中或者在代碼中進(jìn)行硬編碼。這樣會(huì)讓代碼變得難以維護(hù)和修改。而使用 struct tag 可以將這些元信息與 struct 字段緊密關(guān)聯(lián)起來(lái),使代碼更加清晰和易于維護(hù)。
常用的 struct tags
在 Go 的官方 wiki 中,有一個(gè)常用的 struct tags 的庫(kù)的列表,我復(fù)制在下面了,感興趣的同學(xué)可以看看源碼,再繼續(xù)深入學(xué)習(xí)。
以上就是本文的全部?jī)?nèi)容,如果覺(jué)得還不錯(cuò)的話歡迎點(diǎn)贊,轉(zhuǎn)發(fā)和關(guān)注,感謝支持。
參考文章:
https://github.com/golang/go/wiki/Well-known-struct-tags
到此這篇關(guān)于為什么 Go 語(yǔ)言 struct 要使用 tags的文章就介紹到這了,更多相關(guān)Go 語(yǔ)言 struct 要使用 tags內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go來(lái)合并兩個(gè)csv的實(shí)現(xiàn)示例
本文主要介紹了Go來(lái)合并兩個(gè)csv的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Go語(yǔ)言JSON編解碼神器之marshal的運(yùn)用
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中JSON編解碼神器——marshal的運(yùn)用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09Go語(yǔ)言學(xué)習(xí)之時(shí)間函數(shù)使用詳解
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中時(shí)間函數(shù)的使用方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的可以參考一下2022-04-04Go語(yǔ)言基礎(chǔ)語(yǔ)法和基本數(shù)據(jù)類(lèi)型知識(shí)鞏固
這篇文章主要為大家介紹了Go語(yǔ)言基礎(chǔ)語(yǔ)法和基本數(shù)據(jù)類(lèi)型知識(shí)鞏固,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Go語(yǔ)言實(shí)現(xiàn)順序存儲(chǔ)的線性表實(shí)例
這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)順序存儲(chǔ)的線性表的方法,實(shí)例分析了Go語(yǔ)言實(shí)現(xiàn)線性表的定義、插入、刪除元素等的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03Golang基于Vault實(shí)現(xiàn)敏感數(shù)據(jù)加解密
數(shù)據(jù)加密是主要的數(shù)據(jù)安全防護(hù)技術(shù)之一,敏感數(shù)據(jù)應(yīng)該加密存儲(chǔ)在數(shù)據(jù)庫(kù)中,降低泄露風(fēng)險(xiǎn),本文將介紹一下利用Vault實(shí)現(xiàn)敏感數(shù)據(jù)加解密的方法,需要的可以參考一下2023-07-07