validator.struct() 不触发自定义 tag 校验,是因为未提前调用 validate.registervalidation("myrule", myrulefunc) 注册规则;跨字段校验需用 registerstructvalidation;使用框架时须向其 validator 实例注册,而非新实例;中文提示需逐个 registertranslation 并绑定 translator。

validator.Struct() 为什么没触发自定义 tag 校验
常见现象是结构体字段加了 validate:"required,myrule",但调用 validator.Struct() 后 myrule 完全没执行——根本原因是 validator 不认识这个 tag,没注册对应函数。
必须显式注册:validate.RegisterValidation("myrule", myRuleFunc),且该函数签名必须是 func(fl validator.FieldLevel) bool。注意:注册要在任何校验调用前完成,通常放 init() 或 main() 开头。
- 注册晚于第一次
validator.Struct()调用 → 自定义规则静默失效 - 函数返回
true表示通过,false表示失败(不是“是否合法”,而是“是否满足条件”) - 字段值需用
fl.Field().Interface()获取,类型断言要自己处理,比如fl.Field().Interface().(string)
如何让自定义校验访问其他字段(跨字段校验)
比如 ConfirmPassword 必须等于 Password,但默认 FieldLevel 只能拿到当前字段。得换用 StructLevel 注册方式。
validate.RegisterStructValidation(myStructLevelFunc, User{}),函数签名为 func(sl validator.StructLevel),里面可通过 sl.CurrentStruct.Interface() 拿到整个结构体指针,再反射取其他字段。
立即学习“go语言免费学习笔记(深入)”;
- 别直接用
sl.CurrentStruct.FieldByName("Password")—— 它返回的是reflect.Value,要调.Interface()才能比较 - 如果结构体嵌套深,用
sl.Top().FieldByName("XXX")更安全,避免误取嵌入字段 - StructLevel 校验在所有 FieldLevel 之后执行,所以字段级错误(如
required)会先报出,不会被跨字段逻辑掩盖
validator.New() 和默认 validator 实例的区别在哪
直接用 validator.New() 创建新实例,和用全局 validator.DefaultValidator(或 validator.New() 单次复用)行为不同:前者不带已注册的自定义规则、翻译器、结构体缓存,是干净但“空”的实例。
多数 Web 框架(如 Gin、Echo)内部用的是单例 validator,默认已预注册常用规则(email, url 等),但你的自定义规则只存在于你注册的那个实例上。
- 用框架时,务必向它的 validator 实例注册规则,比如 Gin 的
gin.Validator是个接口,需赋值给engine.Validator = &CustomValidator{} - 自己 new 出来的 validator,每次都要重新注册规则 + 翻译器,否则
Translate()会 panic - 性能上,复用一个 validator 实例比反复 new 更好,它内部有 struct 缓存,避免重复反射解析 tag
中文错误提示怎么稳定输出,而不是乱码或 panic
核心是两步:注册翻译器 + 绑定到 validator 实例。用 ut.New(...) 初始化 UniversalTranslator,再调 en := ut.New(...).GetTranslator("zh"),最后 v.RegisterTranslation("required", en, ...)。
容易漏掉的是:每个要翻译的 tag 都得单独注册翻译函数,不能只注册一次就覆盖全部。比如 required、min、myrule 都要各自 RegisterTranslation。
- 翻译函数里用
fe.Translate(...)获取字段名,别硬编码;fe.Param是 tag 的参数(如min=8的8) - 如果用
v.StructCtx(ctx, obj),ctx 必须包含ut.Translator,否则Translate()返回空字符串 - 中文字段名显示异常?检查结构体字段是否有
json:tag,validator 默认用字段名,但翻译器可能按json名匹配——统一用label:tag 显式指定更稳










