Go语言结构体标签,就是在结构体中的一段字符串,有点像PHP中的注解,有严格的格式要求,通常用于反射包里的方法来访问它,标签用来声明结构体中字段的属性。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"username"`
Age int `json:"userage"`
}
func main() {
myself := User{"Skn1fe", 23}
jsondata, err := json.Marshal(myself)
if err != nil {
fmt.Println("格式错误")
} else {
fmt.Printf("User结构体转json:%s\n", jsondata)
}
}
输出结果:
User结构体转json:{"username":"Skn1fe","userage":23}
可以看出"encoding/json"
包的json.Marshal()
方法作用就是把结构体转换为json,它读取了User结构体里面的标签,json键值对的键为定义的标签名,结构体的名字起了辅助作用,同时定义了字段数据类型。json.Unmarshal()
可以把json字符串转换为结构体,在很多第三方包方法都会读取结构体标签。 注意在标签中的外层符号是键盘Tab键上方的键,不是单引号。
AnimalId int64 gorm:"column:beast_id"
type User struct {
Name string `gorm:"<-:create"` // 允许读和创建
Name string `gorm:"<-:update"` // 允许读和更新
Name string `gorm:"<-"` // 允许读和写(创建和更新)
Name string `gorm:"<-:false"` // 允许读,禁止写
Name string `gorm:"->"` // 只读(除非有自定义配置,否则禁止写)
Name string `gorm:"->;<-:create"` // 允许读和写
Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)
Name string `gorm:"-"` // 读写操作均会忽略该字段
}
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `data1:"test1" data2:"test2"`
Age string `json:"test"`
}
func main() {
user := User{"Skn1fe", "23"}
user_value := reflect.ValueOf(user) //获取变量的值
user_type := reflect.TypeOf(user) //获取类型
fmt.Println(user_value, user_type)
//反射的用法,获取结构体标签的值
name_data := user_type.Field(0) //user第一个字段
name_tag_data := name_data.Tag.Get("data2") //获取结构体第一个字段的Tag(标签)里面键为data2的值
fmt.Println("name_data:", name_tag_data)
}
输出结果:
{Skn1fe 23} main.User
name_data: test2
type User struct {
ID int `_`
Name string `valid:"string;maxsize(10);minsize(3)"`
Age int `valid:"number;range(0,150)"`
Email string `valid:"email"`
}
// 接口:方法的集合,实现这个接口中的所有方法,就实现了这个接口。
type Validation struct {
Data interface{} //接收各种结构体数据,空接口可以接受任何数据类型
Errors []error
}
// 验证结构体
func (this *Validation) Validate() {
// todo 编写验证逻辑
//获取它runtime数据
rundata := reflect.TypeOf(this.Data)
//校验数据是否是结构体
if rundata.Kind() != reflect.Struct {
panic("数据类型不是结构体")
}
//循环遍历结构体字段,获取标签内容,再进行校验
for i := 0; i < rundata.NumField(); i++ {
//获取字段的标签
tag := rundata.Field(i).Tag.Get("valid")
curValidator := this.getValidator(tag)
//调用验证器方法,把字段的值传递进去
//fmt.Println(rundata.Field(i))
valid, err := curValidator.Validate(reflect.ValueOf(this.Data).Field(i).Interface())
if !valid && err != nil {
this.Errors = append(this.Errors, err)
}
}
}
var MinRe = regexp.MustCompile(`minsize\((\d+)\)`)
var MaxRe = regexp.MustCompile(`maxsize\((\d+)\)`)
// 通过tag内容返回结构体字段
func (this *Validation) getValidator(tag string) Validator {
//"string;maxsize(10);minsize(3)"
//解析tag内容
tagArgs := strings.Split(tag, ";")
//根据小标志生成对应验证器
switch tagArgs[0] {
case "string":
strValidator := &StringValidator{}
for _, str := range tagArgs[1:] {
switch {
case MaxRe.MatchString(str):
fmt.Sscanf(str, "maxsize(%d)", &strValidator.Max)
case MinRe.MatchString(str):
fmt.Sscanf(str, "minsize(%d)", &strValidator.Min)
}
}
if strValidator.Min > strValidator.Max {
panic("最小值不能大于最大值")
}
return strValidator
case "number":
numberValidator := &NumberValidator{}
fmt.Sscanf(tagArgs[1], "range(%d,%d)", &numberValidator.Min, &numberValidator.Max)
if numberValidator.Min > numberValidator.Max {
panic("最小值不能大于最大值")
}
return numberValidator
case "email":
return &EmailValidator{}
default:
return &DefaultValidator{}
}
}
// 多态通过接口实现
// 定义验证器的接口
type Validator interface {
//验证器的方法
Validate(interface{}) (bool, error)
}
// 缺省的验证器类,不验证
type DefaultValidator struct {
}
func (this *DefaultValidator) Validate(data interface{}) (bool, error) {
return true, nil
}
type StringValidator struct {
Min int
Max int
}
func (this *StringValidator) Validate(data interface{}) (bool, error) {
//把数据从接口类型转化成string类型
str := data.(string)
//判断字符串的长度是否在范围内
length := len(str)
if length < this.Min || length > this.Max {
return false, fmt.Errorf("字符串长度不在范围内")
}
return true, nil
}
type NumberValidator struct {
Min int
Max int
}
func (this *NumberValidator) Validate(data interface{}) (bool, error) {
number := data.(int)
if number < this.Min || number > this.Max {
return false, fmt.Errorf("数字不在范围内")
}
return true, nil
}
// 邮箱正则
var emailRegexp = regexp.MustCompile(`^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$`)
// 定义email的验证器
type EmailValidator struct {
}
func (this *EmailValidator) Validate(data interface{}) (bool, error) {
//把数据从接口类型转化成string类型
str := data.(string)
if !emailRegexp.MatchString(str) {
return false, fmt.Errorf("邮箱格式不正确")
}
return true, nil
}
func main() {
//创建一个用户对象
user := User{
ID: 1,
Name: "sh",
Age: -20,
Email: "1234567890",
}
//创建一个验证器对象
vd := &Validation{user, nil}
vd.Validate()
for _, err := range vd.Errors {
fmt.Println(err)
}
}
输出结果:
字符串长度不在范围内
数字不在范围内
邮箱格式不正确