商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Gosort.Interface的基本使用

Gosort.Interface的基本使用

  发布于2026-07-21 阅读(0)

扫一扫,手机访问

在 Go 语言里,排序这件事,其实核心就围绕着一个接口——sort.Interface。它就像是给排序算法和待排序数据之间定下的一份“契约”,让算法无需关心具体的数据类型,只要数据能遵守这个契约,就能被优雅地排序。

一个通用的排序算法,其实只需要知道三件事:序列有多长?怎么比较两个元素谁大谁小?怎么交换两个元素的位置?没错,这就是 sort.Interface 要求实现的三个方法:

package sort
type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

换句话说,只要你的类型实现了这三个方法,就能直接调用 sort.Sort 来排序了。

举个最简单的例子:对一个字符串切片排序。我们可以定义一个全新的类型 StringSlice,然后给它配上这三个方法:

type StringSlice []string

func (x StringSlice) Len() int           { return len(x) }
func (x StringSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x StringSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }

func main() {
    s := []string{"a", "c", "b"}
    sort.Sort(StringSlice(s))
    fmt.Println(s) // [a b c]
}

注意 Less 方法里用的是 < 符号,这表示按升序排列。如果你想降序,改一下符号就行。

基础类型的切片排序

因为字符串切片排序实在太常见了,Go 标准库干脆直接帮你封装好了 sort.StringSlice 类型,你直接用就行:

s := []string{"a", "c", "b"}
sort.Sort(sort.StringSlice(s))

甚至还有更简洁的 sort.Strings 函数:

s := []string{"a", "c", "b"}
sort.Strings(s)

对于 []int[]float64[]string 这类基础类型的切片,直接用下面这几个函数就对了:

sort.Ints
sort.Floats
sort.Strings

结构体元素类型切片排序

但现实需求往往更复杂。比如你有一个 Person 结构体切片,里面包含 NameScoreAge 字段,现在想按 Name 排序:

type Person struct {
    Name  string
    Score int
    Age   int
}

type Persons []Person

func (p Persons) Len() int           { return len(p) }
func (p Persons) Less(i, j int) bool { return p[i].Name < p[j].Name }
func (p Persons) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
    p := Persons{
        {"c", 90, 30},
        {"b", 100, 10},
        {"c", 90, 20},
    }
    sort.Sort(p)
    fmt.Println(p) // [{b 100 10} {c 90 30} {c 90 20}]
}

如果需求再加一层:当 Name 相同时,按 Score 排序;Score 也相同时,再按 Age 排序。那只需把 Less 方法改得更精细一些:

func (p Persons) Less(i, j int) bool {
    if p[i].Name != p[j].Name {
        return p[i].Name < p[j].Name
    }
    if p[i].Score != p[j].Score {
        return p[i].Score < p[j].Score
    }
    return p[i].Age < p[j].Age
}

这样排序结果就会变成:

[{b 100 10} {c 90 20} {c 90 30}]

其实还有更简洁的方式——sort.Slice。它默认帮你实现了 LenSwap,你只需要传入切片和一个比较函数(Less 逻辑)即可:

p := Persons{
    {"c", 90, 30},
    {"b", 100, 10},
    {"c", 90, 20},
}
sort.Slice(p, func(i, j int) bool {
    if p[i].Name != p[j].Name {
        return p[i].Name < p[j].Name
    }
    if p[i].Score != p[j].Score {
        return p[i].Score < p[j].Score
    }
    return p[i].Age < p[j].Age
})
fmt.Println(p) // [{b 100 10} {c 90 20} {c 90 30}]

任意数据结构排序

最后,sort.Interface 的实现类型不一定是切片。你完全可以用一个结构体来包装排序逻辑,比如下面这个 PersonSort

type Person struct {
    Name  string
    Score int
    Age   int
}

type PersonSort struct {
    p    []Person
    less func(i, j Person) bool
}

func (p PersonSort) Len() int           { return len(p.p) }
func (p PersonSort) Less(i, j int) bool { return p.less(p.p[i], p.p[j]) }
func (p PersonSort) Swap(i, j int)      { p.p[i], p.p[j] = p.p[j], p.p[i] }

func main() {
    p := []Person{
        {"c", 90, 30},
        {"b", 100, 10},
        {"c", 90, 20},
    }
    less := func(i, j Person) bool {
        if i.Name != j.Name {
            return i.Name < j.Name
        }
        if i.Score != j.Score {
            return i.Score < j.Score
        }
        return i.Age < j.Age
    }
    sort.Sort(PersonSort{p, less})
    fmt.Println(p) // [{b 100 10} {c 90 20} {c 90 30}]
}

这种方式的好处是:你可以把比较逻辑单独抽出来,甚至动态替换,非常灵活。不过日常开发中,直接用 sort.Slice 往往更省事。

总的来说,Go 的排序设计思路很清晰:定义一个接口,然后让数据去适配它。只要理解了 LenLessSwap 这三个方法,任何自定义类型都能轻松接入排序机制。

本文转载于:https://www.jb51.net/jiaoben/362068yan.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注