校验组件支持强大的递归校验(嵌套校验)特性。如果给定的校验数据中的属性或者键值为struct/map/slice
类型时,将会被自动执行递归校验。我们来看几个示例:
struct
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) type SearchReq struct { Key string `v:"required"` Option SearchOption } type SearchOption struct { Page int `v:"min:1"` Size int `v:"max:100"` } func main() { var ( ctx = gctx.New() req = SearchReq{ Key: "GoFrame", Option: SearchOption{ Page: 1, Size: 10000, }, } ) err := g.Validator().Data(req).Run(ctx) fmt.Println(err) } |
执行后,终端输出:
The Size value `10000` must be equal or lesser than 100 |
slice
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) func main() { type Student struct { Name string `v:"required#Student Name is required"` Age int } type Teacher struct { Name string Students []Student } var ( ctx = gctx.New() teacher = Teacher{} data = g.Map{ "name": "john", "students": `[{"age":2},{"name":"jack", "age":4}]`, } ) err := g.Validator().Assoc(data).Data(teacher).Run(ctx) fmt.Println(err) } |
执行后,终端输出:
Student Name is required |
map
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) func main() { type Student struct { Name string `v:"required#Student Name is required"` Age int } type Teacher struct { Name string Students map[string]Student } var ( ctx = gctx.New() teacher = Teacher{ Name: "Smith", Students: map[string]Student{ "john": {Name: "", Age: 18}, }, } ) err := g.Validator().Data(teacher).Run(ctx) fmt.Println(err) } |
执行后,终端输出:
Student Name is required |
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) func main() { type Student struct { Name string `v:"required"` } type Teacher struct { Students Student } var ( ctx = gctx.New() teacher = Teacher{} data = g.Map{ "students": nil, } ) err := g.Validator().Assoc(data).Data(teacher).Run(ctx) fmt.Println(err) } |
执行后,终端输出:
Student Name is required |
有同学可能会觉得奇怪,明明我都没有传递Student
字段值,为什么还会递归校验Student
结构体里面的Name
字段?这是因为这里的 Student
属性是个空结构体,是带有默认值的(Name
默认值为空字符串)。递归校验里面,虽然 Student
不是必须参数,这个意思是你可以不传递,但是只要传递了就会按照里面属性的校验规则执行校验(带有默认值的空对象也算是有值)。可以对比和以下代码的差别:
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) func main() { type Student struct { Name string `v:"required"` } type Teacher struct { Students *Student } var ( ctx = gctx.New() teacher = Teacher{} data = g.Map{ "students": nil, } ) err := g.Validator().Assoc(data).Data(teacher).Run(ctx) fmt.Println(err) } |
和前一示例的唯一差异在于Student
属性从结构体改为了结构体指针*Student
,这样该属性不是空对象便没有默认值了。执行后,终端输出位空,表示校验通过。