go标准库无unique包,因社区倾向组合解决:先规范化(大小写、空格等业务逻辑)再用map去重;结构体需自定义key或序列化后哈希,核心是明确定义业务重复逻辑。

Go 标准库没有 unique 包,也不存在官方维护的名为 unique 的通用去重包——你遇到的很可能是第三方包(比如 github.com/leebenson/conform 或误传的 github.com/gobuffalo/uuid 等),或是把其他语言(如 Python 的 numpy.unique)概念直接套用到了 Go 上。
为什么找不到 unique 包?
Go 社区倾向于用组合而非魔法函数解决问题。值的“规范化去重”涉及两个正交环节:规范化(normalize)和去重(deduplicate)。二者需按需组合,没有银弹包:
- 规范化取决于业务逻辑:大小写、空格、Unicode 归一化、JSON 序列化一致性等,无法由通用包自动判断
- 去重本身在 Go 中通常用
map或map[any]bool实现,简单高效,无需额外依赖 - 常见被误认作
unique的包(如conform)实际只做结构体字段规范化(如 trim、lower),不提供集合去重能力
如何手动实现字符串值的规范化去重?
以“忽略大小写 + 去首尾空格 + 合并连续空格”为规范化规则,再对切片去重:
func normalize(s string) string {
s = strings.TrimSpace(s)
s = strings.ToLower(s)
s = regexp.MustCompile(`\s+`).ReplaceAllString(s, " ")
return s
}
func uniqueStrings(input []string) []string {
seen := make(map[string]bool)
result := make([]string, 0, len(input))
for _, s := range input {
key := normalize(s)
if !seen[key] {
seen[key] = true
result = append(result, s) // 保留原始值,或 append(result, key) 保留规范化值
}
}
return result
}
注意:normalize 函数必须满足“相等输入 ⇒ 相等输出”,否则去重会失效;若需 Unicode 归一化(如处理带重音字符),需引入 golang.org/x/text/unicode/norm 并调用 norm.NFC.String(s)。
对结构体切片做规范化去重的关键点
结构体不能直接作为 map 的 key,需转为可比对的表示形式:
- 若结构体字段全为可比类型(如
int,string,bool),可用fmt.Sprintf("%v", v)生成 key(仅限调试,性能差且不稳定) - 推荐显式定义规范化方法,例如实现
Key() string方法,内部按需调用strings.ToLower、strconv.FormatInt等 - 更安全的方式是使用
hash/fnv构造哈希值:h := fnv.New64a(); binary.Write(h, binary.LittleEndian, v.Field1); ...,但要注意字节序和字段顺序一致性 - 若结构体含 slice/map/func/channel,必须先序列化(如
json.Marshal)再哈希,且要确保序列化结果稳定(如设置json.Encoder.SetEscapeHTML(false)、排序 map 键)
真正难的不是“怎么去重”,而是“怎么定义两个值在业务意义上算‘重复’”——这个判定逻辑必须由你写清楚,任何包都替代不了这一步。











