Menu
CoddyTech

sort.Interface

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 74 课,共 107 课。

sort 包提供了另一个接口设计的绝佳示例。要对自定义集合排序,你的类型必须实现 sort.Interface:

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

这三个方法为排序算法提供了所需的一切:集合的长度、比较元素的方法,以及交换元素的方法。下面介绍如何让自定义结构体组成的切片支持排序:

type Person struct {
    Name string
    Age  int
}

type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func main() {
    people := []Person{
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 35},
    }
    
    sort.Sort(ByAge(people))
    fmt.Println(people)
    // [{Bob 25} {Alice 30} {Carol 35}]
}

关键在于基于你的切片创建一个命名类型(ByAge)。这样,你就可以为同一份数据定义不同的排序行为。你也可以通过不同的 Less 实现创建 ByName,以便按字母顺序排序。

只要你的类型满足 sort.Interface,就能自动与 sort.Sort()、sort.Reverse() 和 sort.IsSorted() 配合使用。

challenge icon

挑战

简单

让我们构建一个可排序的产品库存系统,展示 Go 的 sort.Interface 的强大功能!你将创建一个 Product 类型,并实现多种排序策略,让同一组产品可以按不同方式排序。

你需要将代码组织在两个文件中:

  • product.go:定义产品类型和排序实现。

    创建一个 Product 结构体,包含三个字段:Name(字符串)、Price(float64)和 Quantity(int)。

    基于 []Product 创建两个命名类型:

    • ByPrice:按价格升序排列产品
    • ByQuantity:按数量降序排列产品(数量最多的排在最前面)

    每个类型都需要实现 sort.Interface 要求的三个方法:Len()、Less(i, j int) 和 Swap(i, j int)。Less 方法用于确定每种类型的排序顺序。

  • main.go:构建并排序产品库存。

    读取排序模式(price 或 quantity),然后读取产品数量,接着读取产品详情。每个产品占三行,分别是名称、价格和数量。

    创建产品切片,根据排序模式使用相应的排序类型对产品进行排序,然后按以下格式打印每个产品:

    [Name]: $[Price] (x[Quantity])

    价格显示为两位小数。

输入内容如下:

  • 第 1 行:排序模式(price 或 quantity)
  • 第 2 行:产品数量
  • 后续各行:产品详情(名称、价格、数量,每个产品占三行)

例如,给定以下输入:

price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25

输出应为:

Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)

再例如,给定以下输入:

quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25

输出应为:

Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)

请注意,只需使用不同的命名类型,相同的产品数据就能按不同方式排序。只要你的类型满足 sort.Interface,就可以与标准库中的 sort.Sort() 无缝配合。

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取排序模式
	var mode string
	fmt.Fscanln(reader, &mode)

	// 读取商品数量
	var count int
	fmt.Fscanln(reader, &count)

	// 读取商品信息
	products := make([]Product, count)
	for i := 0; i < count; i++ {
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		priceStr, _ := reader.ReadString('\n')
		priceStr = strings.TrimSpace(priceStr)
		price, _ := strconv.ParseFloat(priceStr, 64)

		qtyStr, _ := reader.ReadString('\n')
		qtyStr = strings.TrimSpace(qtyStr)
		quantity, _ := strconv.Atoi(qtyStr)

		products[i] = Product{Name: name, Price: price, Quantity: quantity}
	}

	// TODO:根据 mode 对商品排序
	// 如果 mode 是 "price",使用 ByPrice 类型
	// 如果 mode 是 "quantity",使用 ByQuantity 类型
	// 使用 sort.Sort() 和对应的类型进行排序

	// TODO:按以下格式输出每件商品:
	// [Name]: $[Price] (x[Quantity])
	// 使用 fmt.Printf,并用 %.2f 格式化价格
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器