不能。标准 validator 无内置 unique 标签,需手动注册自定义函数:用 map 记录已见元素遍历判重,仅对 slice 类型生效,空或单元素 slice 视为合法,要求元素类型可比较。

validator 能不能直接校验切片元素唯一性?
不能。标准 validator(如 go-playground/validator/v10)没有内置的 unique 或 distinct 标签,对 []string、[]int 等切片类型做“元素不重复”校验必须手动扩展。
怎么写一个支持切片去重校验的自定义验证函数?
核心是注册一个自定义函数,用 map 记录已见元素,遍历判断是否重复。注意要兼容不同元素类型(int、string、struct 字段等),且避免 panic:
- 只对 slice 类型生效,非 slice 直接返回 true(跳过)
- 空 slice 或单元素 slice 视为合法,无需校验
- 元素类型必须可比较(不能是 map/slice/func),否则运行时报
panic: runtime error: comparing uncomparable type - 示例注册方式:
v8 := validator.New() v8.RegisterValidation("unique", func(fl validator.FieldLevel) bool { v := fl.Field() if v.Kind() != reflect.Slice { return true } if v.Len()
为什么用 Interface() 取值容易出错?
因为 v.Index(i).Interface() 返回 interface{},而 map key 要求可比较;如果切片元素是 struct 且含不可比较字段(比如内嵌 slice),就会 panic。更安全的做法是按需序列化或提取可比较字段:
- 对
[]string、[]int等基础类型,直接用Interface()没问题 - 对结构体切片,建议改用字段级校验:例如
type Item struct { ID string `validate:"required,unique"` },再配合自定义函数只取ID字段值去重 - 或者用
json.Marshal转成字符串作 key(性能略低,但规避不可比较问题) - 不要在校验函数里对
nilslice 做v.Len()—— 先判v.IsNil()
在 Gin 或 Echo 中怎么绑定并触发这个校验?
只要结构体字段带上 validate:"unique" 标签,并确保你用的是已注册该 tag 的 validator 实例即可。Gin 默认用的是自己的 binding,需显式替换:
- Gin:调用
gin.SetMode(gin.ReleaseMode)后,用engine.Validator = &customValidator{v8}(实现binding.StructValidator接口) - Echo:通过
e.Validator = &echoValidator{v8}注入 - 标签写法示例:
type Req struct { Tags []string `json:"tags" validate:"required,unique"` } - 错误提示默认是 “Key: ‘Req.Tags’ Error:Field validation for ‘Tags’ failed on the ‘unique’ tag”,如需友好提示,得在 validator 的
TranslationFunc里覆盖
真正麻烦的不是写校验逻辑,而是让 validator 在 panic 前就拒绝不可比较类型 —— 这点很容易被忽略,直到线上接口突然 500。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











