Nested Structs & Slices
Check walks the entire field tree automatically. You don't have to opt in or call anything special to validate nested data.
Plain nested structs
Every exported field is visited recursively, and tags fire just like top-level fields:
type Address struct {
Street string `valid:"required" label:"街道"`
Zip string `valid:"required;alphanumeric" label:"邮编"`
}
type Profile struct {
Name string `valid:"required" label:"姓名"`
Address Address // no tag needed; fields inside are still validated
}Slices of structs
Each element is validated independently. Errors come back in declaration order, then per-element order:
type Item struct {
SKU string `valid:"required" label:"SKU"`
Qty int `valid:"min:1" label:"数量"`
}
type Order struct {
Items []Item `valid:"required" label:"商品"`
}
errs, _ := govalid.Check(Order{
Items: []Item{
{SKU: "A1", Qty: 5},
{SKU: "", Qty: 0},
},
})
// errs[0]: "SKU不能为空" (from element 1)
// errs[1]: "数量应大于1" (from element 1)The outer field's required rule still applies, so an empty Items: nil slice yields its own 购物车不能为空-style error.
Embedded (anonymous) structs
Embedded structs are walked just like named fields. This works even when the embedded type itself is unexported — the validator descends into the type's exported fields without panicking on the parent's Interface() call:
type embeddedBase struct {
Name string `valid:"required" label:"姓名"`
}
type Form struct {
embeddedBase
Other string `valid:"required" label:"其他"`
}
errs, _ := govalid.Check(Form{})
// errs[0]: "姓名不能为空"
// errs[1]: "其他不能为空"Pointers to structs
Pointer fields are dereferenced automatically. Nil pointers are safe — you'll get Cfg不能为空 from required rather than a panic:
type Config struct {
Host string `valid:"required" label:"主机"`
}
type Service struct {
Cfg *Config `valid:"required" label:"配置"`
}Slices of pointers to structs
Slices of *T aren't recursed into element-by-element today — only the outer slice's own rules fire. If you need per-element validation, use []T instead, or run a manual loop:
for i, item := range pointers {
if errs, ok := govalid.Check(item); !ok {
// ...
}
}Validating top-level slices
Check accepts a slice of structs at the top level too. Every element is validated:
items := []Item{{SKU: "A1", Qty: 1}, {SKU: "", Qty: 0}}
errs, ok := govalid.Check(items)Validating maps and channels
Only structs and slices-of-structs are considered "validatable containers". Maps, channels and primitives at the top level return (nil, true) — the validator silently passes them. To validate map values that are structs, iterate manually:
for _, v := range users {
if errs, ok := govalid.Check(v); !ok {
// ...
}
}