嵌套结构体校验不生效,主因是字段未导出或omitempty误用:字段须首字母大写才能被validator反射读取;omitempty对普通struct无效;嵌套校验必须用Validate.Struct()而非Validate.Var();切片需加dive;time.Time应转字符串配合datetime规则校验。

嵌套结构体校验不生效,八成是字段没导出或 omitempty 用错了位置——不是 validator 不支持嵌套,而是它根本没看到你的字段。
字段必须首字母大写才能被 validator 读到
validator 依赖反射访问字段,而 Go 反射只能读取导出字段(即首字母大写)。小写字段哪怕 tag 写得再全,也会被直接跳过,不报错、不提示、不校验。
-
Name string `validate:"required"`✅ 生效 -
name string `validate:"required"`❌ 静默忽略 - 嵌套结构体里的字段同理:内层
Age要大写,age就不算数 - 跨字段比较如
eqfield=Password,右边的Password也必须是导出字段名,不能是password或 JSON key
嵌套 struct 字段加 omitempty 没用
omitempty 只对指针、map、slice、interface{} 等类型生效;对普通 struct 类型(如 Address)加了也白加,只要字段存在,哪怕全是零值(Address{}),validator 仍会递归进子字段校验。
-
Addr *Address `validate:"omitempty,required"`→Addr == nil时跳过整个校验 -
Addr Address `validate:"omitempty,required"`→omitempty被忽略,Addr{}仍会校验其内部City string `validate:"required"` - 想让非指针嵌套字段“可选”,得去掉
required,只留业务规则,比如validate:"min=1"或validate:"email"
Validate.Struct() 和 Validate.Var() 别混用
传结构体指针给 Validate.Var() 是常见误用:它只会检查指针是否为 nil,完全不会跑字段校验逻辑。嵌套校验必须用 Validate.Struct()。
立即学习“go语言免费学习笔记(深入)”;
-
validate.Struct(req)✅ 自动识别字段 tag,递归校验嵌套、dive 切片、处理omitempty -
validate.Var(req, "required")❌ 只校验req是否为nil,和字段无关 -
validate.Var(&req, "required")❌ 同样无效,Var()不理解结构体上下文 - 切片字段需显式加
dive:Items []Item `validate:"dive,required"`,否则只校验切片长度
时间字段别直接校验 time.Time
validator 对 time.Time 类型无原生支持,直接加 validate:"required" 会 panic 或静默失败。正确做法是用字符串接收,再配 datetime 规则。
-
CreatedAt time.Time `validate:"required"`❌ 不推荐,行为不可控 -
CreatedAt string `validate:"required,datetime=2006-01-02T15:04:05Z07:00"`✅ 明确格式,可校验 - 若必须用
time.Time,需先转为字符串再校验,或注册自定义验证器 -
datetime规则中的 layout 必须和输入字符串完全匹配,多一个空格都失败
最易被忽略的一点:嵌套结构体里所有层级的字段都要导出,且 omitempty 的作用范围仅限于它右边的规则——它不阻止 required 先执行,所以 omitempty,required 实际上等价于 required。


















