Go結構體標簽


結構體標簽定義

通過 reflect.Type 獲取結構體成員信息 reflect.StructField 結構中的 Tag 被稱為結構體標簽(Struct Tag)。結構體標簽是對結構體字段的額外信息標簽。
Tag是結構體在編譯階段關聯到成員的元信息字符串,在運行的時候通過反射的機制讀取出來。
結構體標簽由一個或多個鍵值對組成。鍵與值使用冒號分隔,值用雙引號括起來。鍵值對之間使用一個空格分隔,具體的格式如下:

`key1:"value1" key2:"value2" key3:"value3"...`  // 鍵值對用空格分隔

key會指定反射的解析方式包含 json(JSON標簽)、 orm(Beego標簽)、gorm(GORM標簽)、bson(MongoDB標簽)、form(表單標簽)、binding(表單驗證標簽).這些系統使用標簽設定字段在處理時應該具備的特殊屬性和可能發生的行為。這些信息都是靜態的,無須實例化結構體,可以通過反射獲取到。

json標簽

JSON數組可以用於編碼Go語言的數組和slice。
將Go語言中結構體slice轉為JSON的過程叫編組(marshaling),編組通過json.Marshal函數完成。
如果在結構體slice編碼成JSON的時候使用自定義的成員名,可以使用結構體成員Tag來實現。
示例:

type User1 struct {
	Name string `json:"username"` // 編碼后的字段名為 username
	Age  int    `json:"userage"`  // 編碼后的字段名為 userage
	Sex  string `json:"usersex"`  // 編碼后的字段名為 usersex
}

type User2 struct {
	Name string `json:"username"`
	Age  int    `json:"userage"`
	Sex  string // 編碼后的字段名為 Sex
}

type User3 struct {
	Name string `json:"username"`
	Age  int    `json:"-"` // 字段不進行序列化	Sex  string
}

func main() {
	u1 := User1{"ares", 20, "man"}
	jsondata1, err := json.Marshal(u1)
	if err != nil {
		fmt.Println("格式錯誤")
	} else {
		fmt.Printf("User1結構體轉json:%s\n", jsondata1)
	}

	u2 := User2{"ares", 20, "man"}
	jsondata2, err := json.Marshal(u2)
	if err != nil {
		fmt.Println("格式錯誤")
	} else {
		fmt.Printf("User2結構體轉json:%s\n", jsondata2)
	}

	u3 := User3{"ares", 20, "man"}
	jsondata3, err := json.Marshal(u3)
	if err != nil {
		fmt.Println("格式錯誤")
	} else {
		fmt.Printf("User3結構體轉json:%s\n", jsondata3)
	}
}

輸出為:

User1結構體轉json:{"username":"ares","userage":20,"usersex":"man"}
User2結構體轉json:{"username":"ares","userage":20,"Sex":"man"}
User3結構體轉json:{"username":"ares","Sex":"man"}

"encoding/json"包的json.Marshal()方法作用就是把結構體轉換為json,它讀取了User結構體里面的標簽,json鍵值對的鍵為定義的標簽名,結構體的名字起了輔助作用,同時定義了字段數據類型。json.Unmarshal()可以把json字符串轉換為結構體,在很多第三方包方法都會讀取結構體標簽。

標簽選項:

標簽選項 使用說明
- 字段不進行序列化 例:json:"-"
omitempy 類型零值或空值,序列化時忽略該字段 例:json:",omitempy" 字段名省略的話用結構體字段名
Type 重新指定字段類型 例:json:"age,string"

gorm標簽

模型是標准的 struct,由基本數據類型以及實現了 Scanner 和 Valuer 接口的自定義類型及其指針或別名組成。
GORM 傾向於約定,而不是配置。默認情況下,GORM 使用 ID 作為主鍵,使用結構體名的 蛇形復數 作為表名,字段名的 蛇形 作為列名,並使用 CreatedAt、UpdatedAt 字段追蹤創建、更新時間。
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 創建表時,不會創建被忽略的字段。
如果想要保存 UNIX(毫/納)秒時間戳,而不是 time,只需簡單地將 time.Time 修改為 int 即可。

字段標簽

聲明 model 時,tag 是可選的,GORM 支持以下 tag:

標簽名 說明
column 指定 db 列名
type 列數據類型,推薦使用兼容性好的通用類型,例如:所有數據庫都支持 bool、int、uint、float、string、time、bytes 並且可以和其他標簽一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 這樣指定數據庫數據類型也是支持的。在使用指定數據庫數據類型時,它需要是完整的數據庫數據類型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
size 指定列大小,例如:size:256
primaryKey 指定列為主鍵
unique 指定列為唯一
default 指定列的默認值
precision 指定列的精度
scale 指定列大小
not null 指定列為 NOT NULL
autoIncrement 指定列為自動增長
autoIncrementIncrement 自動步長,控制連續記錄之間的間隔
embedded 嵌套字段
embeddedPrefix 嵌入字段的列名前綴
autoCreateTime 創建時追蹤當前時間,對於 int 字段,它會追蹤秒級時間戳,您可以使用 nano/milli 來追蹤納秒、毫秒時間戳,例如:autoCreateTime:nano
autoUpdateTime 創建/更新時追蹤當前時間,對於 int 字段,它會追蹤秒級時間戳,您可以使用 nano/milli 來追蹤納秒、毫秒時間戳,例如:autoUpdateTime:milli
index 根據參數創建索引,多個字段使用相同的名稱則創建復合索引,查看 索引 獲取詳情
uniqueIndex 與 index 相同,但創建的是唯一索引
check 創建檢查約束,例如 check:age > 13,查看 約束 獲取詳情
<- 設置字段寫入的權限, <-:create 只創建、<-:update 只更新、<-:false 無寫入權限、<- 創建和更新權限
-> 設置字段讀的權限,->:false 無讀權限
- 忽略該字段,- 無讀寫權限
comment 遷移時為字段添加注釋

關聯標簽

GORM 允許通過標簽為關聯配置外鍵、約束、many2many 表:

標簽名 說明
foreignKey 指定當前模型的列作為連接表的外鍵
references 指定引用表的列名,其將被映射為連接表外鍵
polymorphic 指定多態類型,比如模型名
polymorphicValue 指定多態值、默認表名
many2many 指定連接表表名
joinForeignKey 指定連接表的外鍵列名,其將被映射到當前表
joinReferences 指定連接表的外鍵列名,其將被映射到引用表
constraint 關系約束,例如:OnUpdate、OnDelete

form標簽

Gin中提供了模型綁定,將表單數據和模型進行綁定,方便參數校驗和使用。
模型綁定:

// 表單數據
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 {
        ...
    }
    // 獲取表單數據局
    args := Email {
        Email:     email.Email,
        Password:  email.Password,
    }
    // 對參數進行后續使用
    ...
}

通過 form:"email" 對表單email數據進行綁定。然后通過Bind()、ShouldBind()等方法獲取參數值。

binding標簽

Gin 主要提供了兩組綁定方法 Must bind 與 Should bind 。gin/binding 內置模型綁定實現,將請求數據提取到合適的綁定器。
Must bind:驗證不通過,就會被終止或拋出特定的錯誤頁面
Should bind:存在綁定錯誤,這個錯誤會被返回,需要自行處理相應的請求和錯誤。
Gin 框架本身已經實現了多種綁定,通常用來綁定來自請求數據,有不同的結構體實例與之對應。其實現的綁定有 JSON, XML, Form,Query,FormPost,FormMultipart,ProtoBuf,MsgPack,YAML,Uri。
Gin對於數據的校驗使用的是 validator.v10 包,該包提供多種數據校驗方法,通過binding:""標簽來進行數據校驗。
校驗規則見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 參數值包含設置子串 binding:"contains=ares"是否包含ares字符串
excludes 參數值不包含設置子串 binding:"excludes=ares"是否不包含ares字符串
startswith 字符串前綴 binding:"startswith=ares"是否以tom開頭
endswith 字符串前綴 binding:"endswith=ares"是否以tom結尾

范圍校驗

范圍驗證: 切片、數組和map、字符串,驗證其長度;數值,驗證大小范圍。

標簽選項 使用說明 示例
len 參數值等於給定值 binding:"len=3"等於3
ne 不等於 binding:"ne=3"不等於3
max 最大值,小於等於參數值 binding:"max=3"小於等於3
min 最小值,大於等於參數值 binding:"min=3"大於等於3
lte 參數值小於等於給定值 binding:"lte=3"小於等於3
gte 參數值大於等於給定值 binding:"gte=3"大於等於3
lt 參數值小於給定值 binding:"lt=3"小於3
gt 參數值大於給定值 binding:"gt=3"大於3
oneof 參數值只能是枚舉值中的一個,值必須是數值或字符串,以空格分隔,如果字符串中有空格,將字符串用單引號包圍 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"
email 合法郵箱校驗 binding:"email"
url 合法的URL binding:"url"
uri 合法的URI binding:"uri"
uuid uuid驗證 binding:"uuid"
datetime 合法時間格式值校驗 binding:"datetime=2006-01-02"
json JSON數據驗證 validate:"json"
numeric 數值驗證 正則:^[-+]?[0-9]+(?:\\.[0-9]+)?$ validate:"numeric"
number 整數驗證 正則:^[0-9]+$ validate:"number"
alpha 字母字符串驗證 正則:^[a-zA-Z]+$ validate:"alpha"
alphanum 字母數字字符串驗證 正則:^[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"`
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM