Skip to content

sort ​

阅读提示

  • 适用版本:Go 1.21+(示例在 Go 1.22 下验证)· 前置知识:语法基础-切片 · 阅读时长:约 10 分钟

TIP

如果你是 1.21 版本以上的开发者,我建议使用slices标准库来进行排序,它支持泛型,API 设计更加合理。

在 go 中的sort包下提供了官方实现的排序方法,大部分可以直接开箱即用。倘若想要对结构体进行排序的话必须实现sort.Interface下的三个方法Len() swap() Less()。由于官方已经帮我们实现了Float64Slice StringSlice IntSlice三个类型,所以这三个类型可以不用我们自己实现直接使用即可。

go
type Interface interface {
   // 长度方法
   Len() int

   // 比较方法
   Less(i, j int) bool

   // 交换方法
   Swap(i, j int)
}

整型排序 ​

go
func main() {
   ints := []int{1, 2, 3, 111, 5, 99, 23, 5, 66}
   sort.Ints(ints)
}

浮点排序 ​

go
func main() {
   floats := []float64{1.0, 2.5, 3.8, 1.11, 5.5, 99.99999, 23.9999, 5.66, 66}
   sort.Float64s(floats)
   fmt.Println(floats)
}

字符串排序 ​

go
func main() {
   strings := []string{"helloworld", "aaa", "bbb", "ccc"}
   sort.Strings(strings)
}

逆向排序 ​

需要先进行sort.Reverse包装再进行排序

go
func main() {
  floats := []float64{1.0, 2.5, 3.8, 1.11, 5.5, 99.99999, 23.9999, 5.66, 66}
  sort.Sort(sort.Reverse(sort.Float64Slice(floats)))
  fmt.Println(floats)
}

自定义排序 ​

如果想要自定义结构体排序的话,就必须实现三个方法。

go
type Person struct {
  UserId   string
  Username string
  Age      int
  Address  string
}

type PersonSlice []Person

//返回切片的长度
func (p PersonSlice) Len() int {
  return len(p)
}

//比较方法
func (p PersonSlice) Less(i, j int) bool {
  return p[i].Age < p[j].Age
}

//交换方法
func (p PersonSlice) Swap(i, j int) {
  p[i], p[j] = p[j], p[i]
}

由于是根据年龄比较的,所有结果是根据年龄的大小来排序。

go
func main() {
   persons := []Person{{
      UserId:   "1",
      Username: "wyh",
      Age:      18,
      Address:  "us",
   }, {
      UserId:   "2",
      Username: "jack",
      Age:      17,
      Address:  "ch",
   }, {
      UserId:   "3",
      Username: "mike",
      Age:      15,
      Address:  "india",
   }}

   sort.Sort(PersonSlice(persons))

   fmt.Println(persons)
}

是否有序 ​

判断一个切片是否有序,其内部并不会进行排序操作,而是通过循环调用Less()来判断

go
func main() {
   persons := []Person{{
      UserId:   "1",
      Username: "wyh",
      Age:      18,
      Address:  "us",
   }, {
      UserId:   "2",
      Username: "jack",
      Age:      17,
      Address:  "ch",
   }, {
      UserId:   "3",
      Username: "mike",
      Age:      15,
      Address:  "india",
   }}

   sort.Sort(PersonSlice(persons))

   println(sort.IsSorted(PersonSlice(persons)))
}

完整示例 ​

下面的程序可以直接运行:复制到文件后执行 go run main.go,或粘贴到 Go Playground 运行。

go
package main

import (
	"fmt"
	"sort"
)

type User struct {
	Name string
	Age  int
}

func main() {
	users := []User{{"Bob", 30}, {"Alice", 25}, {"Carol", 30}}
	sort.SliceStable(users, func(i, j int) bool { return users[i].Age < users[j].Age })
	fmt.Println(users)

	nums := []int{3, 1, 2}
	sort.Ints(nums)
	fmt.Println(nums, sort.SearchInts(nums, 2))
}

预期输出:

text
[{Alice 25} {Bob 30} {Carol 30}]
[1 2 3] 1

常见错误与踩坑 ​

  • sort.Slice 不稳定。 相等元素可能被交换;需要保持原顺序时用 sort.SliceStable。
  • 比较函数必须是严格弱序。 写成 <= 而不是 < 会导致未定义结果。
  • sort.Search* 系列要求数据已排序。 在无序切片上搜索会静默返回错误结果。
  • Less 要尽量轻量。 它会被调用 O(n log n) 次,昂贵计算应提前算好。
  • 优先用现成辅助函数。 sort.Ints、sort.Strings、sort.SliceStable 已覆盖大多数场景。

更新记录 ​

  • 2026-10-14:新增"阅读提示"、完整可运行示例(含预期输出)、常见错误与踩坑清单,以及本更新记录。