Go 泛型约束:从 comparable 到自定义类型集
泛型让容器与算法复用更干净,但约束写多了,API 会开始「吵」。少即是多。
自 Go 1.18 起,类型参数成为语言一部分。日常最常用的内建约束是 any 与 comparable;更细的需求则用接口定义类型集。
类型集,不是「方法列表」那么简单
约束接口既可以列出方法,也可以用元素类型枚举允许的底层类型:
type Number interface {
~int | ~int64 | ~float64
}
func Sum[T Number](xs []T) T {
var s T
for _, v := range xs {
s += v
}
return s
}
~ 表示包含以该类型为底层类型的自定义类型,这在包装基础类型时很关键。
comparable 的适用面
map 的键、相等比较,需要 comparable。注意:切片、函数、含切片字段的结构体等不可比。若你的泛型 API 依赖 ==,约束里写清楚,比运行期 panic 更友好。
设计经验
- 先接口后泛型:若行为多态足够,不必上类型参数。
- 约束贴近操作:只用到
+就别引入一堆无关方法。 - 避免过度抽象:为两个调用点写三层泛型工具包,往往得不偿失。
- 导出约束要克制:包内约束可以细;对外 API 宁可简单。
小结
泛型是消除重复的手术刀,不是展示类型体操的舞台。约束写到「刚好能编译通过你需要的操作」即可,剩下的留给清晰的命名与测试。