cmp.compare仅适用于整数、浮点数、字符串等ordered类型,返回-1/0/1;不支持结构体、切片、map或interface{},否则编译失败;nan比较有特殊规则,-0.0与0.0视为相等。

cmp.Compare 只能用于 comparable 类型,且返回 -1/0/1;别拿它去比结构体、切片、map 或 interface{},会编译失败。
cmp.Compare 适用场景和限制
cmp.Compare 是 Go 1.21 标准库新增的泛型函数,专为 ordered 类型设计——也就是支持 、<code>==、> 的基础类型:整数、浮点数、字符串。
它不是 go-cmp(github.com/google/go-cmp)里的那个 cmp.Equal,两者名字像,但包、用途、约束完全不同,混用直接报错。
- 合法调用:
cmp.Compare(42, 100)、cmp.Compare("a", "b")、cmp.Compare(float64(3.14), math.NaN()) - 非法调用:
cmp.Compare(struct{X int}{}, struct{X int}{})→ 编译错误:type does not satisfy ~int | ~float64 | ~string - NaN 特殊行为:
cmp.Compare(x, math.NaN())总是返回 1(除非 x 也是 NaN);cmp.Compare(math.NaN(), math.NaN())返回 0 - 浮点零值:
cmp.Compare(-0.0, 0.0)返回 0,符合 IEEE 754 语义
cmp.Less 更轻量,适合排序逻辑
cmp.Less 是 cmp.Compare 的布尔简化版,只回答“是否小于”,没有三态语义。它在 slices.SortFunc 等需要比较函数的地方更自然。
例如写一个泛型排序函数时,直接传 cmp.Less 比写 func(a, b T) bool { return cmp.Compare(a, b) 更简洁、无额外分支开销。
- 推荐用于:
slices.SortFunc(items, cmp.Less)、自定义二分查找的谓词 - 不推荐用于:需要区分“等于”或“大于”的上下文(比如实现堆的上浮/下沉逻辑需三态)
- 性能上和
cmp.Compare(x, y) 几乎一致,但少一次整数比较,对热点路径有微弱优势
别把 cmp.Compare 当 go-cmp 的 cmp.Equal 用
这是最常发生的误用:看到都叫 cmp,就以为 cmp.Compare(a, b) == 0 能替代测试里的结构体比较——完全不行。
-
cmp.Compare不处理指针解引用、不递归字段、不忽略私有字段、不支持选项定制 -
cmp.Equal(来自go-cmp)才面向测试,支持cmpopts.IgnoreFields、cmp.Comparer、protocmp.Transform()等 - 结构体比较失败时先看包导入:是
"cmp"还是"github.com/google/go-cmp/cmp"?拼错包名或 import 错路径会导致静默行为差异 - 如果真想在泛型函数里做“类似 Equal”的判断,得自己定义约束,比如
type Equaler[T any] interface{ Equal(T) bool },而不是依赖cmp.Compare
Ordered 约束不能扩展,别试图绕过
ordered 是一个封闭接口,由编译器硬编码支持的底层类型组成。你无法给自定义类型添加 ordered 约束,哪怕它实现了 Compare 方法或重载了 。
例如:type MyInt int 可以用 cmp.Compare,因为底层是 int;但 type Version [3]int 即使你写了 func (v Version) Less(other Version) bool,也无法满足 ordered ——Go 不支持用户扩展该约束。
- 要比较自定义聚合类型,必须用
go-cmp+cmp.Comparer显式注册比较逻辑 - 或者退回到
func(a, b Version) int手写三态函数,再封装成泛型工具 - 试图用
~Version去模拟ordered会触发编译错误:cannot use ~Version (type constraint) as type ordered
cmp 和第三方 go-cmp 不仅 API 不兼容,连错误提示都指向不同方向——前者编译期拒斥类型,后者运行期深挖字段。选错包,debug 时看到的报错信息根本不在一个维度上。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











