常见问题
我必须传指针吗?
值或指针都可以。Check 接受 interface{}——指针会被自动解引用, nil 被视为"没有什么需要校验",不会 panic。
go
govalid.Check(form) // 值
govalid.Check(&form) // 指针如果你需要带指针接收者的 Validate() error 方法被触发,请传指针。 值接收者两种调用都会触发。
怎么把字段做成"可选但格式校验"?
省略 required 即可。格式型校验器(email、mobile……)会把空 字符串视为通过:
go
type Form struct {
Backup string `valid:"email"` // 允许空,但有值时必须合法
}怎么强制 boolean 必须为 true?
用 required。govalid 的 required 把 bool 视为"非零值",也就是 true:
go
type Terms struct {
Accepted bool `valid:"required" label:"服务条款"`
}怎么逐元素校验切片?
把它写成 struct 切片,然后给该 struct 的字段加标签。govalid 会自动 遍历元素:
go
type Item struct {
Name string `valid:"required"`
}
type Order struct {
Items []Item `valid:"required"`
}[]*Item(指针切片)目前不支持逐元素校验——请用 []Item 或自己 loop。
怎么取回字段原始的错误类型?
目前 *ErrContext 没有暴露 Unwrap,所以 errors.As 无法穿透到 Validate() 方法返回的底层错误。两种常见绕开方案:
- 把需要的数据编码进错误字符串。
- 让
Validate()通过侧通道返回错误(例如把它们记到 form 结构体 本身上)。
这是已知的粗糙之处——如果它困扰你,欢迎提 issue。
为什么 min/max 忽略我的 bool 字段?
因为它们只对数值类型生效(有符号/无符号整型与浮点数)。布尔字段 请用 required 或 list:true,false。
为什么 equal 是按字符串比较?
equal 用 fmt.Sprintf("%v", …) 把两边都字符串化。这让它能跨异构 类型工作(int vs string),代价是无法捕捉细微的类型不匹配。 如果你需要严格的类型相等比较,写一个自定义校验器即可。
我能在同一个结构体上跑多次校验吗?
可以。从调用方角度看 govalid 是无状态的——Check 可以用同一个值 反复调用。每次调用都会重新遍历整个结构体。
在热加载校验器 map 的场景下安全吗?
Checkers、errorTemplateChinese 等的读取在没有写者时是并发安全的。 如果你必须在运行时改动它们,请用自己的互斥锁包好,并在切换时暂停 所有正在飞的请求。