go語言中struct標簽詳解
一、結構體標簽介紹
結構體的字段除了名字和類型外,還可以有一個可選的標簽(tag):它是一個附屬于字段的字符串,可以是文檔或其他的重要標記。
Tag是結構體在編譯階段關聯(lián)到成員的元信息字符串,在運行的時候通過反射的機制讀取出來。
結構體標簽由一個或多個鍵值對組成。鍵與值使用冒號分隔,值用雙引號括起來。鍵值對之間使用一個空格分隔
`key1:"value1" key2:"value2" key3:"value3"...` // 鍵值對用空格分隔
注意:冒號左右不能有空格,否則運行輸出結果可能不對,所以,編寫 Tag 時,必須嚴格遵守鍵值對的規(guī)則。結構體標簽的解析代碼的容錯能力很差,一旦格式寫錯,編譯和運行時都不會提示任何錯誤
key會指定反射的解析方式包含 :json(JSON標簽)、 orm(Beego標簽)、gorm(GORM標簽)、bson(MongoDB標簽)、form(表單標簽)、binding(表單驗證標簽).
這些系統(tǒng)使用標簽設定字段在處理時應該具備的特殊屬性和可能發(fā)生的行為。這些信息都是靜態(tài)的,無須實例化結構體,可以通過反射獲取到。
二、json標簽
將Go語言中結構體slice轉為JSON的過程叫編組(marshaling),編組通過json.Marshal函數(shù)完成
json.Unmarshal()可以把json字符串轉換為結構體,在很多第三方包方法都會讀取結構體標簽。
type User struct { Name string `json:"username"` // 編碼后的字段名為 username Age int `json:"userage"` // 編碼后的字段名為 userage Sex string // 編碼后的字段名為 Sex Hobby string `json:"-"` // 字段不進行序列化 } func main() { u1 := User{"zhangsan", 20, "男", "eat"} jsondata1, err := json.Marshal(u1) if err != nil { fmt.Println("格式錯誤") } else { fmt.Printf("User結構體轉json:%s\n", jsondata) } //輸出 User結構體轉json:{"username":"zhangsan","userage":20,"Sex":"男"}
標簽選項 | 使用說明 |
- | 字段不進行序列化 例:json:"-" |
omitempy | 類型零值或空值,序列化時忽略該字段 例:json:",omitempy" 字段名省略的話用結構體字段名 |
Type | 重新指定字段類型 例:json:"age,string" |
三、gorm標簽
GORM 傾向于約定,而不是配置。默認情況下,GORM 使用 ID 作為主鍵,使用結構體名的 蛇形復數(shù) 作為表名,字段名的 蛇形 作為列名,并使用 CreatedAt、UpdatedAt 字段追蹤創(chuàng)建、更新時間。
GORM 默認定義一個 gorm.Model 結構體,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt,可以嵌套入自建結構體,tag名大小寫不敏感,建議使用camelCase風格,多個標簽定義用分號(;)分隔:
// gorm.Model 的定義 type Model struct { ID uint `gorm:"primaryKey"` CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` }
示例:
type AddUserAuth struct { gorm.BaseModel UUID string `gorm:"column:user_uuid;comment:用戶UUID;type:varchar(100);"` // 用戶UUID User string `gorm:"column:user_name;comment:用戶名稱;type:varchar(50);"` // 用戶登錄名 Cluster string `gorm:"column:cluster_name;comment:集群名稱;type:varchar(50);"` // k8s集群 NameSpace string `gorm:"column:namespace;comment:命名空間;type:varchar(50);"` // 命名空間 ServiceName string ` gorm:"column:service_name;comment:應用名稱;type:varchar(50);"` // 應用名稱 ServiceType string `gorm:"column:service_type;comment:應用類型;type:varchar(50);"` // 應用類型 }
生成的建表語句如下:
CREATE TABLE `add_user_auths` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `created_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL, `deleted_at` datetime DEFAULT NULL, `user_uuid` varchar(100) DEFAULT NULL COMMENT '用戶UUID', `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名稱', `cluster_name` varchar(50) DEFAULT NULL COMMENT '集群名稱', `namespace` varchar(50) DEFAULT NULL COMMENT '命名空間', `service_name` varchar(50) DEFAULT NULL COMMENT '應用名稱', `service_type` varchar(50) DEFAULT NULL COMMENT '應用類型', PRIMARY KEY (`id`), KEY `idx_add_user_auths_deleted_at` (`deleted_at`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
使用 GORM Migrator 創(chuàng)建表時,不會創(chuàng)建被忽略的字段。
如果想要保存 UNIX(毫/納)秒時間戳,而不是 time,只需簡單地將 time.Time 修改為 int 即可。
字段標簽:
聲明 model 時,tag 是可選的,GORM 支持以下 tag:
標簽名 | 說明 |
column | 指定 db 列名 |
type | 列數(shù)據(jù)類型,推薦使用兼容性好的通用類型,例如:所有數(shù)據(jù)庫都支持 bool、int、uint、float、string、time、bytes 并且可以和其他標簽一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 這樣指定數(shù)據(jù)庫數(shù)據(jù)類型也是支持的。在使用指定數(shù)據(jù)庫數(shù)據(jù)類型時,它需要是完整的數(shù)據(jù)庫數(shù)據(jù)類型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT |
size | 指定列大小,例如:size:256 |
primaryKey | 指定列為主鍵 |
unique | 指定列為唯一 |
default | 指定列的默認值 |
precision | 指定列的精度 |
scale | 指定列大小 |
not null | 指定列為 NOT NULL |
autoIncrement | 指定列為自動增長 |
autoIncrementIncrement | 自動步長,控制連續(xù)記錄之間的間隔 |
embedded | 嵌套字段 |
embeddedPrefix | 嵌入字段的列名前綴 |
autoCreateTime | 創(chuàng)建時追蹤當前時間,對于 int 字段,它會追蹤秒級時間戳,您可以使用 nano/milli 來追蹤納秒、毫秒時間戳,例如:autoCreateTime:nano |
autoUpdateTime | 創(chuàng)建/更新時追蹤當前時間,對于 int 字段,它會追蹤秒級時間戳,您可以使用 nano/milli 來追蹤納秒、毫秒時間戳,例如:autoUpdateTime:milli |
index | 根據(jù)參數(shù)創(chuàng)建索引,多個字段使用相同的名稱則創(chuàng)建復合索引,查看 索引 獲取詳情 |
uniqueIndex | 與 index 相同,但創(chuàng)建的是唯一索引 |
check | 創(chuàng)建檢查約束,例如 check:age > 13,查看 約束 獲取詳情 |
<- | 設置字段寫入的權限, <-:create 只創(chuàng)建、<-:update 只更新、<-:false 無寫入權限、<- 創(chuàng)建和更新權限 |
-> | 設置字段讀的權限,->:false 無讀權限 |
- | 忽略該字段,- 無讀寫權限 |
comment | 遷移時為字段添加注釋 |
關聯(lián)標簽:
GORM 允許通過標簽為關聯(lián)配置外鍵、約束、many2many 表:
標簽名 | 說明 |
foreignKey | 指定當前模型的列作為連接表的外鍵 |
references | 指定引用表的列名,其將被映射為連接表外鍵 |
polymorphic | 指定多態(tài)類型,比如模型名 |
polymorphicValue | 指定多態(tài)值、默認表名 |
many2many | 指定連接表表名 |
joinForeignKey | 指定連接表的外鍵列名,其將被映射到當前表 |
joinReferences | 指定連接表的外鍵列名,其將被映射到引用表 |
constraint | 關系約束,例如:OnUpdate、OnDelete |
四、form標簽
Gin中提供了模型綁定,將表單數(shù)據(jù)和模型進行綁定,方便參數(shù)校驗和使用。
模型綁定:
// 表單數(shù)據(jù) type LoginForm struct { UserName string `form:"username"` Password string `form:"password"` Email string `form:"email"` } // model 或 service 層Model type Email struct { Email string Password string } func EmailLogin (c *gin.Context) { var email LoginForm if err := c.ShouldBind(&email); err != nil { ... } // 獲取表單數(shù)據(jù)局 args := Email { Email: email.Email, Password: email.Password, } // 對參數(shù)進行后續(xù)使用 ... }
通過 form:"email" 對表單email數(shù)據(jù)進行綁定。然后通過Bind()、ShouldBind()等方法獲取參數(shù)值。
五、binding標簽
Gin 主要提供了兩組綁定方法 Must bind 與 Should bind 。gin/binding 內置模型綁定實現(xiàn),將請求數(shù)據(jù)提取到合適的綁定器。
Must bind:驗證不通過,就會被終止或拋出特定的錯誤頁面
Should bind:存在綁定錯誤,這個錯誤會被返回,需要自行處理相應的請求和錯誤。
Gin 框架本身已經(jīng)實現(xiàn)了多種綁定,通常用來綁定來自請求數(shù)據(jù),有不同的結構體實例與之對應。其實現(xiàn)的綁定有 JSON, XML, Form,Query,F(xiàn)ormPost,FormMultipart,ProtoBuf,MsgPack,YAML,Uri。
Gin對于數(shù)據(jù)的校驗使用的是 validator.v10 包,該包提供多種數(shù)據(jù)校驗方法,通過binding:""標簽來進行數(shù)據(jù)校驗。
校驗規(guī)則見github:validator
示例:
type LoginForm struct { Email string `form:"email" binding:"email"` UserName string `form:"username" binding:"username"` Password string `form:"password" binging:"required,min=6,max=10"` }
特殊符號:
符號 | 說明 |
, | 分隔多個標簽選項,逗號之間不能有空格 |
- | 該字段不做校驗 |
| | 使用多個選項,滿足其中一個即可 |
必須校驗
標簽選項 | 說明 | 示例 |
required | 表示該字段值必輸設置,且不能為默認值 | binding:required |
omitempty | 如果字段未設置,則忽略它 | binding:reqomitemptyuired |
字符串校驗
標簽選項 | 使用說明 | 示例 |
contains | 參數(shù)值包含設置子串 | binding:"contains=ares"是否包含ares字符串 |
excludes | 參數(shù)值不包含設置子串 | binding:"excludes=ares"是否不包含ares字符串 |
startswith | 字符串前綴 | binding:"startswith=ares"是否以tom開頭 |
endswith | 字符串前綴 | binding:"endswith=ares"是否以tom結尾 |
范圍校驗
范圍驗證: 切片、數(shù)組和map、字符串,驗證其長度;數(shù)值,驗證大小范圍。
標簽選項 | 使用說明 | 示例 |
len | 參數(shù)值等于給定值 | binding:"len=3"等于3 |
ne | 不等于 | binding:"ne=3"不等于3 |
max | 最大值,小于等于參數(shù)值 | binding:"max=3"小于等于3 |
min | 最小值,大于等于參數(shù)值 | binding:"min=3"大于等于3 |
lte | 參數(shù)值小于等于給定值 | binding:"lte=3"小于等于3 |
gte | 參數(shù)值大于等于給定值 | binding:"gte=3"大于等于3 |
lt | 參數(shù)值小于給定值 | binding:"lt=3"小于3 |
gt | 參數(shù)值大于給定值 | binding:"gt=3"大于3 |
oneof | 參數(shù)值只能是枚舉值中的一個,值必須是數(shù)值或字符串,以空格分隔,如果字符串中有空格,將字符串用單引號包圍 | binding:"oneof=red green" |
字段校驗
標簽選項 | 使用說明 |
eqcsfield | 跨不同結構體字段相等,比如struct1 field1 是否等于struct2 field2 |
necsfield | 跨不同結構體字段不相等 |
eqfield | 同一結構體字段相等驗證,例如:輸入兩次密碼 |
nefield | 同一結構體字段不相等驗證 |
gtefield | 大于等于同一結構體字段 |
ltefield | 小于等于同一結構體字段 |
示例:
// 不同結構體校驗 type S1 struct { F1 string `validate:eqcsfield=S2.F2` S2 struct { F2 string } } // 同一結構體字段相同校驗 type Email struct { Email string `validate:"lte=4"` Pwd string `validate:"min=10"` Pwd2 string `validate:"eqfield=Pwd"` } // 同一結構體字段不相等 type User struct { Name string `validate:"lte=4"` Age int `validate:"min=20"` Password string `validate:"min=10,nefield=Name"` }
其他校驗
標簽選項 | 使用說明 | 示例 |
ip | 合法IP地址校驗 | binding:"ip" |
合法郵箱校驗 | binding:"email" | |
url | 合法的URL | binding:"url" |
uri | 合法的URI | binding:"uri" |
uuid | uuid驗證 | binding:"uuid" |
datetime | 合法時間格式值校驗 | binding:"datetime=2006-01-02" |
json | JSON數(shù)據(jù)驗證 | validate:"json" |
numeric | 數(shù)值驗證 正則:^[-+]?[0-9]+(?:\\.[0-9]+)?$ | validate:"numeric" |
number | 整數(shù)驗證 正則:^[0-9]+$ | validate:"number" |
alpha | 字母字符串驗證 正則:^[a-zA-Z]+$ | validate:"alpha" |
alphanum | 字母數(shù)字字符串驗證 正則:^[a-zA-Z0-9]+$ | validate:"alphanum" |
ascii | Ascii 字符驗證 | validate:"ascii" |
六、ini標簽
ini 是 Windows 上常用的配置文件格式, go-ini是 Go 語言中用于操作 ini 文件的第三方庫。
若使用ini格式配置,需要將配置文件字段映射到結構體變量,如果鍵名與字段名不相同,那么需要在結構標簽中指定對應的鍵名。標準庫encoding/json、encoding/xml解析時可以將鍵名直接對應到字段名,而go-ini庫不可以,所以需要在結構體標簽指定對應鍵名。
## 配置文件 cnf.ini user_name = ares age = 20 // 配置文件映射 結構體 type Config struct { UserName string `ini:"user_name"` // ini標簽指定下鍵名 Age string `ini:"age"` }
總結
到此這篇關于go語言中struct標簽的文章就介紹到這了,更多相關go struct標簽內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang中urlencode與urldecode編碼解碼詳解
這篇文章主要給大家介紹了關于Golang中urlencode與urldecode編碼解碼的相關資料,在Go語言中轉碼操作非常方便,可以使用內置的encoding包來快速完成轉碼操作,Go語言中的encoding包提供了許多常用的編碼解碼方式,需要的朋友可以參考下2023-09-09go mutex互斥鎖使用Lock和Unlock方法占有釋放資源
Go號稱是為了高并發(fā)而生的,在高并發(fā)場景下,勢必會涉及到對公共資源的競爭,當對應場景發(fā)生時,我們經(jīng)常會使用 mutex 的 Lock() 和 Unlock() 方法來占有或釋放資源,雖然調用簡單,但 mutex 的內部卻涉及挺多的,本文來好好研究一下2023-09-09go語言實戰(zhàn)之實現(xiàn)比特幣地址校驗步驟
這篇文章主要介紹了go語言實戰(zhàn)之實現(xiàn)比特幣地址校驗步驟,利用生產(chǎn)的隨機數(shù)采用橢圓加密算法生成公鑰,具體步驟實例代碼請參考下本文2021-05-05