> 文章列表 > 【Go自学】一文搞懂Go Comparable和Ordered类型

【Go自学】一文搞懂Go Comparable和Ordered类型

【Go自学】一文搞懂Go Comparable和Ordered类型

我们在学校Go语言的泛型时会经常使用 interface{} / any来替代所有的数据类型,除此之外我们还可以使用comparable 关键字来指代golang中所有可以用!=或者==来进行比较的元素。我们可以先查看comparable 的源码。

// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable interface{ comparable }

这段话中定义了,布尔值、数字值、字符串、指针、通道、数组以及所有字段都相同的结构体属于comparable 类型。

comparable 比较容易引起误解的一点是很多人容易把他与可排序搞混淆。可比较指的是 可以执行 != == 操作的类型,并没确保这个类型可以执行大小比较( >,<,<=,>= )

  • Comparable:可以使用 == 和 != 比较,非黑即白
  • Ordered:可以使用 > >= < <= 做大小比较,有明确的大小概念

下面一个表格介绍了所有 Go 内置类型的约定

Type Comparable Ordered Description
Boolean
Integer
Float
Complex 分别比较实数和虚数,同时相等则两个复数相等。 如果需要比较大小,需要开发者分别比较实数和虚数。
String 基于字节逐个比较。
Pointer 如果两个指针指向同一个对象或者都为 nil,则两者相等。
Channel 类似 Pointer,两个 Channel 变量只有都为 nil,或者指向同一个 Channel 的时候才相等。
Interface 两个 interface 的 Type 和 Value 值同时相等时,两者才相等。
Struct ⚠️ 仅当 Struct 内所有成员都是 Comparable,这个 Struct 才是 Comparable 的。 如果两个 struct 类型相同,且所有非空成员变量都相等,则两者相等。
Array ⚠️ 仅当成员为 Comparable,Array 才是 Comparable 的。 如果两个 Array 中的每一个元素一一相等时,则两个 Array 相等。
Map
Slice
Func

从上面可以看到,Go 当中绝大多数类型都是可以使用运算符相互比较的,唯独不包含 Slice,Map 和 Func,也有容器类型 Struct、Array 本身的comparable 取决于成员的类型。

一般comparable 类型常用于Go的泛型定义中

另外目前Go语言并没有像 comparable 这样直接内置对应的ordered关键词,所以想要的话需要自己来定义相关接口,比如我们可以参考Go官方包golang.org/x/exp/constraints 如何定义:

// Ordered 代表所有可比大小排序的类型
type Ordered interface {Integer | Float | ~string
}type Integer interface {Signed | Unsigned
}type Signed interface {~int | ~int8 | ~int16 | ~int32 | ~int64
}type Unsigned interface {~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}type Float interface {~float32 | ~float64
}

这里虽然可以直接使用官方包 golang.org/x/exp/constraints ,但因为这个包属于实验性质的 x 包,今后可能会发生非常大变动,所以并不推荐直接使用