Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

slices 包详解

概述

slices 包是 Go 1.21 引入的标准库包,提供了对任意类型切片进行操作的泛型函数集合。

核心功能

  • 切片比较和查找
  • 切片修改操作(插入、删除、替换)
  • 排序和检查排序
  • 最值查找
  • 去重和压缩
  • 迭代器支持
  • 切片复制和扩展

重要说明

  • Go 版本要求:Go 1.21+
  • 泛型实现:所有函数都使用泛型,适用于任意类型的切片
  • 实验性状态:Go 1.21-1.22 为实验性,Go 1.23+ 已稳定

包导入

import "slices"

函数详解(按 A-Z 分类)

A

All

func All[Slice ~[]E, E any](s Slice) iter.Seq2[int, E]

功能: 返回一个迭代器,按正常顺序遍历切片中的索引 - 值对。

参数

  • s Slice - 要遍历的切片

返回值

  • iter.Seq2[int, E] - 产生 (索引,值) 对的迭代器

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bob", "Vera"}
    
    for i, v := range slices.All(names) {
        fmt.Printf("%d : %s\n", i, v)
    }
}

运行结果

0 : Alice
1 : Bob
2 : Vera

AppendSeq

func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice

功能: 将迭代器 seq 中的值追加到切片 s 中,返回扩展后的切片。

参数

  • s Slice - 目标切片
  • seq iter.Seq[E] - 值的迭代器

返回值

  • Slice - 扩展后的切片

示例

package main

import (
    "fmt"
    "iter"
    "slices"
)

func main() {
    // 创建偶数迭代器
    evens := func(yield func(int) bool) {
        for i := 0; i < 5; i++ {
            if !yield(i * 2) {
                return
            }
        }
    }
    
    s := []int{1, 2}
    s = slices.AppendSeq(s, evens)
    
    fmt.Println(s) // [1 2 0 2 4 6 8]
}

Backward

func Backward[Slice ~[]E, E any](s Slice) iter.Seq2[int, E]

功能: 返回一个迭代器,反向遍历切片中的索引 - 值对。

参数

  • s Slice - 要遍历的切片

返回值

  • iter.Seq2[int, E] - 产生 (索引,值) 对的迭代器(从后向前)

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bob", "Vera"}
    
    for i, v := range slices.Backward(names) {
        fmt.Printf("%d : %s\n", i, v)
    }
}

运行结果

2 : Vera
1 : Bob
0 : Alice

B

BinarySearch

func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool)

功能: 在已排序的切片中搜索目标值,返回最早匹配的位置或应插入的位置,以及是否找到。

参数

  • x S - 已排序的切片(升序)
  • target E - 要查找的目标值

返回值

  • int - 目标值的位置或应插入的位置
  • bool - 是否真的找到了目标值

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bill", "Vera"}
    
    idx, found := slices.BinarySearch(names, "Vera")
    fmt.Printf("Vera: %d %v\n", idx, found) // Vera: 2 true
    
    idx, found = slices.BinarySearch(names, "Bill")
    fmt.Printf("Bill: %d %v\n", idx, found) // Bill: 1 true
    
    idx, found = slices.BinarySearch(names, "Bob")
    fmt.Printf("Bob: %d %v\n", idx, found) // Bob: 2 false
}

BinarySearchFunc

func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool)

功能: 与 BinarySearch 类似,但使用自定义比较函数。

参数

  • x S - 已排序的切片
  • target T - 要查找的目标值
  • cmp func(E, T) int - 比较函数(返回负数表示小于,0 表示等于,正数表示大于)

返回值

  • int - 目标值的位置或应插入的位置
  • bool - 是否真的找到了目标值

示例

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 20},
        {"Bob", 25},
        {"Vera", 30},
    }
    
    // 按姓名查找
    idx, found := slices.BinarySearchFunc(people, "Bob", 
        func(p Person, name string) int {
            if p.Name < name {
                return -1
            } else if p.Name > name {
                return 1
            }
            return 0
        })
    
    fmt.Printf("Bob: %d %v\n", idx, found) // Bob: 1 true
}

C

Chunk

func Chunk[Slice ~[]E, E any](s Slice, n int) iter.Seq[Slice]

功能: 返回一个迭代器,产生大小为 n 的连续子切片。

参数

  • s Slice - 要分块的切片
  • n int - 每块的大小

返回值

  • iter.Seq[Slice] - 产生子切片的迭代器

注意

  • 如果 n < 1,函数会 panic
  • 最后一块可能小于 n

示例

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Gopher", 13},
        {"Alice", 20},
        {"Bob", 5},
        {"Vera", 24},
        {"Zac", 15},
    }
    
    for chunk := range slices.Chunk(people, 2) {
        fmt.Println(chunk)
    }
}

运行结果

[{Gopher 13} {Alice 20}]
[{Bob 5} {Vera 24}]
[{Zac 15}]

Clip

func Clip[S ~[]E, E any](s S) S

功能: 移除切片未使用的容量,返回 s[:len(s):len(s)]

参数

  • s S - 要处理的切片

返回值

  • S - 容量被裁剪的切片

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := make([]int, 4, 10)
    fmt.Println(cap(s)) // 10
    
    s = slices.Clip(s)
    fmt.Println(cap(s)) // 4
    fmt.Println(s)      // [0 0 0 0]
}

Clone

func Clone[S ~[]E, E any](s S) S

功能: 返回切片的浅拷贝。

参数

  • s S - 要复制的切片

返回值

  • S - 切片的副本

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s1 := []int{0, 42, -10, 8}
    s2 := slices.Clone(s1)
    
    fmt.Println(s1) // [0 42 -10 8]
    fmt.Println(s2) // [0 42 -10 8]
    
    // 修改原切片不影响副本
    s1[2] = 10
    fmt.Println(s1) // [0 42 10 8]
    fmt.Println(s2) // [0 42 -10 8]
}

Collect

func Collect[E any](seq iter.Seq[E]) []E

功能: 从迭代器收集值到新的切片中。

参数

  • seq iter.Seq[E] - 值的迭代器

返回值

  • []E - 包含所有值的切片

示例

package main

import (
    "fmt"
    "iter"
    "slices"
)

func main() {
    // 创建偶数迭代器
    evens := func(yield func(int) bool) {
        for i := 0; i < 5; i++ {
            if !yield(i * 2) {
                return
            }
        }
    }
    
    s := slices.Collect(evens)
    fmt.Println(s) // [0 2 4 6 8]
}

Compact

func Compact[S ~[]E, E comparable](s S) S

功能: 替换连续的相等元素为单个副本(类似 Unix 的 uniq 命令)。

参数

  • s S - 要处理的切片(会被修改)

返回值

  • S - 修改后的切片(长度可能变小)

注意

  • 会修改原切片的内容
  • 新长度和原长度之间的元素会被清零

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []int{0, 1, 1, 2, 2, 2, 3, 5, 5, 8}
    s = slices.Compact(s)
    fmt.Println(s) // [0 1 2 3 5 8]
}

CompactFunc

func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S

功能: 与 Compact 类似,但使用自定义相等比较函数。

参数

  • s S - 要处理的切片
  • eq func(E, E) bool - 相等比较函数

返回值

  • S - 修改后的切片

示例

package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    names := []string{"bob", "BOB", "alice", "ALICE", "Vera", "VERA"}
    
    // 忽略大小写去重
    names = slices.CompactFunc(names, func(a, b string) bool {
        return strings.EqualFold(a, b)
    })
    
    fmt.Println(names) // [bob alice Vera]
}

Compare

func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int

功能: 比较两个切片的元素。

参数

  • s1 S - 第一个切片
  • s2 S - 第二个切片

返回值

  • 0 - 如果 s1 == s2
  • -1 - 如果 s1 < s2
  • +1 - 如果 s1 > s2

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{1, 2, 3}
    s3 := []int{1, 2, 4}
    
    fmt.Println(slices.Compare(s1, s2)) // 0 (相等)
    fmt.Println(slices.Compare(s1, s3)) // -1 (s1 < s3)
    fmt.Println(slices.Compare(s3, s1)) // 1 (s3 > s1)
}

CompareFunc

func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int

功能: 与 Compare 类似,但使用自定义比较函数。

参数

  • s1 S1 - 第一个切片
  • s2 S2 - 第二个切片
  • cmp func(E1, E2) int - 比较函数

返回值

  • 0 - 如果所有元素都相等
  • 第一个不匹配元素的比较结果
  • 如果长度不同,返回长度比较结果

示例

package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    s1 := []string{"Alice", "Bob"}
    s2 := []string{"ALICE", "BOB"}
    
    // 忽略大小写比较
    result := slices.CompareFunc(s1, s2, func(a, b string) int {
        return strings.Compare(strings.ToLower(a), strings.ToLower(b))
    })
    
    fmt.Println(result) // 0 (忽略大小写后相等)
}

Concat

func Concat[S ~[]E, E any](slices ...S) S

功能: 连接多个切片,返回新的切片。

参数

  • slices ...S - 可变数量的切片

返回值

  • S - 连接后的新切片

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s1 := []int{0, 1, 2}
    s2 := []int{3, 4}
    s3 := []int{5, 6}
    
    result := slices.Concat(s1, s2, s3)
    fmt.Println(result) // [0 1 2 3 4 5 6]
}

Contains

func Contains[S ~[]E, E comparable](s S, v E) bool

功能: 检查切片是否包含指定值。

参数

  • s S - 要搜索的切片
  • v E - 要查找的值

返回值

  • bool - 是否找到

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, 3, 4, 5}
    
    fmt.Println(slices.Contains(nums, 3))  // true
    fmt.Println(slices.Contains(nums, 10)) // false
}

ContainsFunc

func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool

功能: 检查切片中是否有至少一个元素满足给定条件。

参数

  • s S - 要搜索的切片
  • f func(E) bool - 条件函数

返回值

  • bool - 是否有元素满足条件

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{2, 4, 6, 8}
    
    // 检查是否有负数
    hasNegative := slices.ContainsFunc(nums, func(n int) bool {
        return n < 0
    })
    fmt.Println("Has negative:", hasNegative) // false
    
    // 检查是否有偶数
    hasEven := slices.ContainsFunc(nums, func(n int) bool {
        return n%2 == 0
    })
    fmt.Println("Has even:", hasEven) // true
}

D

Delete

func Delete[S ~[]E, E any](s S, i, j int) S

功能: 从切片中删除元素 s[i:j],返回修改后的切片。

参数

  • s S - 要修改的切片
  • i int - 起始索引
  • j int - 结束索引(不包含)

返回值

  • S - 修改后的切片

注意

  • 如果 j > len(s)s[i:j] 不是有效切片,会 panic
  • 时间复杂度:O(len(s)-i)
  • 会清零被删除的元素

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []string{"a", "b", "c", "d", "e"}
    
    // 删除索引 1 到 3 的元素
    s = slices.Delete(s, 1, 3)
    fmt.Println(s) // [a e]
}

DeleteFunc

func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S

功能: 从切片中删除所有满足条件的元素。

参数

  • s S - 要修改的切片
  • del func(E) bool - 删除条件函数

返回值

  • S - 修改后的切片

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{0, 1, 2, 3, 5, 8}
    
    // 删除所有奇数
    nums = slices.DeleteFunc(nums, func(n int) bool {
        return n%2 != 0
    })
    
    fmt.Println(nums) // [0 2 8]
}

E

Equal

func Equal[S ~[]E, E comparable](s1, s2 S) bool

功能: 检查两个切片是否相等(长度相同且所有元素相等)。

参数

  • s1 S - 第一个切片
  • s2 S - 第二个切片

返回值

  • bool - 是否相等

注意

  • 空切片和 nil 切片视为相等
  • NaN 不相等

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{1, 2, 3}
    s3 := []int{1, 2, 4}
    
    fmt.Println(slices.Equal(s1, s2)) // true
    fmt.Println(slices.Equal(s1, s3)) // false
    
    // 空切片和 nil 切片
    var nilSlice []int
    emptySlice := []int{}
    fmt.Println(slices.Equal(nilSlice, emptySlice)) // true
}

EqualFunc

func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool

功能: 使用自定义相等函数检查两个切片是否相等。

参数

  • s1 S1 - 第一个切片
  • s2 S2 - 第二个切片
  • eq func(E1, E2) bool - 相等比较函数

返回值

  • bool - 是否相等

示例

package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    s1 := []string{"Alice", "Bob"}
    s2 := []string{"ALICE", "BOB"}
    
    // 忽略大小写比较
    equal := slices.EqualFunc(s1, s2, func(a, b string) bool {
        return strings.EqualFold(a, b)
    })
    
    fmt.Println(equal) // true
}

G

Grow

func Grow[S ~[]E, E any](s S, n int) S

功能: 增加切片的容量,保证可以追加至少 n 个元素而无需重新分配。

参数

  • s S - 要扩展的切片
  • n int - 需要保证的额外容量

返回值

  • S - 容量扩展后的切片

注意

  • 如果 n 为负数或太大,会 panic

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []int{0, 42, -10, 8}
    fmt.Println(cap(s)) // 4
    
    s = slices.Grow(s, 4)
    fmt.Println(cap(s)) // 至少 8
    
    // 现在可以追加 4 个元素而无需重新分配
    s = append(s, 1, 2, 3, 4)
    fmt.Println(s) // [0 42 -10 8 1 2 3 4]
}

I

Index

func Index[S ~[]E, E comparable](s S, v E) int

功能: 返回值 v 在切片中第一次出现的索引,如果不存在返回 -1。

参数

  • s S - 要搜索的切片
  • v E - 要查找的值

返回值

  • int - 索引位置,或 -1

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, 3, 4, 5}
    
    fmt.Println(slices.Index(nums, 3))  // 2
    fmt.Println(slices.Index(nums, 10)) // -1
}

IndexFunc

func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int

功能: 返回第一个满足条件 f(s[i]) 的索引 i,如果没有返回 -1。

参数

  • s S - 要搜索的切片
  • f func(E) bool - 条件函数

返回值

  • int - 索引位置,或 -1

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, -3, 4, -5}
    
    idx := slices.IndexFunc(nums, func(n int) bool {
        return n < 0
    })
    
    fmt.Printf("First negative at index %d\n", idx) // 2
}

Insert

func Insert[S ~[]E, E any](s S, i int, v ...E) S

功能: 在索引 i 处插入值 v...,返回修改后的切片。

参数

  • s S - 要修改的切片
  • i int - 插入位置
  • v ...E - 要插入的值

返回值

  • S - 修改后的切片

注意

  • 如果 i > len(s),会 panic
  • 时间复杂度:O(len(s) + len(v))

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []string{"Alice", "Bob", "Vera", "Zac"}
    
    // 在索引 1 处插入 "Bill" 和 "Billie"
    s = slices.Insert(s, 1, "Bill", "Billie")
    fmt.Println(s) // [Alice Bill Billie Bob Vera Zac]
}

IsSorted

func IsSorted[S ~[]E, E cmp.Ordered](x S) bool

功能: 检查切片是否按升序排序。

参数

  • x S - 要检查的切片

返回值

  • bool - 是否已排序

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    sorted := []int{1, 2, 3, 4, 5}
    unsorted := []int{1, 3, 2, 4, 5}
    
    fmt.Println(slices.IsSorted(sorted))   // true
    fmt.Println(slices.IsSorted(unsorted)) // false
}

IsSortedFunc

func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool

功能: 使用自定义比较函数检查切片是否已排序。

参数

  • x S - 要检查的切片
  • cmp func(a, b E) int - 比较函数

返回值

  • bool - 是否已排序

示例

package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    names := []string{"alice", "Bob", "VERA"}
    
    // 检查是否按字母顺序排序(忽略大小写)
    sorted := slices.IsSortedFunc(names, func(a, b string) int {
        return strings.Compare(strings.ToLower(a), strings.ToLower(b))
    })
    
    fmt.Println(sorted) // true
}

M

Max

func Max[S ~[]E, E cmp.Ordered](x S) E

功能: 返回切片中的最大值。

参数

  • x S - 要查找最大值的切片

返回值

  • E - 最大值

注意

  • 如果切片为空,会 panic
  • 对于浮点数,NaN 会传播

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{10, 42, -5, 8}
    max := slices.Max(nums)
    fmt.Println(max) // 42
}

MaxFunc

func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E

功能: 使用自定义比较函数返回切片中的最大值。

参数

  • x S - 要查找最大值的切片
  • cmp func(a, b E) int - 比较函数

返回值

  • E - 最大值

示例

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 20},
        {"Bob", 25},
        {"Vera", 30},
    }
    
    // 按年龄找最年长的人
    oldest := slices.MaxFunc(people, func(a, b Person) int {
        return a.Age - b.Age
    })
    
    fmt.Println(oldest.Name) // Vera
}

Min

func Min[S ~[]E, E cmp.Ordered](x S) E

功能: 返回切片中的最小值。

参数

  • x S - 要查找最小值的切片

返回值

  • E - 最小值

注意

  • 如果切片为空,会 panic
  • 对于浮点数,NaN 会传播

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{10, 42, -10, 8}
    min := slices.Min(nums)
    fmt.Println(min) // -10
}

MinFunc

func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E

功能: 使用自定义比较函数返回切片中的最小值。

参数

  • x S - 要查找最小值的切片
  • cmp func(a, b E) int - 比较函数

返回值

  • E - 最小值

示例

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 20},
        {"Bob", 15},
        {"Vera", 30},
    }
    
    // 按年龄找最年轻的人
    youngest := slices.MinFunc(people, func(a, b Person) int {
        return a.Age - b.Age
    })
    
    fmt.Println(youngest.Name) // Bob
}

R

Repeat

func Repeat[S ~[]E, E any](x S, count int) S

功能: 返回一个新切片,将原切片重复指定次数。

参数

  • x S - 要重复的切片
  • count int - 重复次数

返回值

  • S - 重复后的新切片

注意

  • 如果 count 为负数或结果溢出,会 panic
  • 结果永远不会是 nil

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []int{0, 1, 2, 3}
    repeated := slices.Repeat(s, 2)
    fmt.Println(repeated) // [0 1 2 3 0 1 2 3]
}

Replace

func Replace[S ~[]E, E any](s S, i, j int, v ...E) S

功能: 用给定的值 v 替换 s[i:j],返回修改后的切片。

参数

  • s S - 要修改的切片
  • i int - 起始索引
  • j int - 结束索引(不包含)
  • v ...E - 替换的值

返回值

  • S - 修改后的切片

注意

  • 如果 j > len(s)s[i:j] 无效,会 panic

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    s := []string{"Alice", "Bob", "Cat", "Zac"}
    
    // 替换索引 1 到 2 的元素
    s = slices.Replace(s, 1, 2, "Bill", "Billie")
    fmt.Println(s) // [Alice Bill Billie Zac]
}

Reverse

func Reverse[S ~[]E, E any](s S)

功能: 原地反转切片中的元素。

参数

  • s S - 要反转的切片

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bob", "Vera"}
    slices.Reverse(names)
    fmt.Println(names) // [Vera Bob Alice]
}

S

Sort

func Sort[S ~[]E, E cmp.Ordered](x S)

功能: 将切片按升序排序。

参数

  • x S - 要排序的切片

注意

  • 对于浮点数,NaN 排在其他值之前

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{42, -10, 0, 8}
    slices.Sort(nums)
    fmt.Println(nums) // [-10 0 8 42]
}

SortFunc

func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int)

功能: 使用自定义比较函数对切片排序(升序)。

参数

  • x S - 要排序的切片
  • cmp func(a, b E) int - 比较函数

注意

  • 排序不稳定(相等元素的顺序可能改变)

示例 1:忽略大小写排序

package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    names := []string{"VERA", "alice", "Bob"}
    
    slices.SortFunc(names, func(a, b string) int {
        return strings.Compare(strings.ToLower(a), strings.ToLower(b))
    })
    
    fmt.Println(names) // [alice Bob VERA]
}

示例 2:多字段排序

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Gopher", 13},
        {"Alice", 55},
        {"Bob", 24},
        {"Alice", 20},
    }
    
    // 先按姓名,再按年龄排序
    slices.SortFunc(people, func(a, b Person) int {
        if a.Name != b.Name {
            if a.Name < b.Name {
                return -1
            }
            return 1
        }
        return a.Age - b.Age
    })
    
    fmt.Println(people)
    // [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}]
}

SortStableFunc

func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int)

功能: 稳定排序切片(保持相等元素的原始顺序)。

参数

  • x S - 要排序的切片
  • cmp func(a, b E) int - 比较函数

示例

package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Gopher", 13},
        {"Alice", 55},
        {"Bob", 24},
        {"Alice", 20},
    }
    
    // 按姓名稳定排序
    slices.SortStableFunc(people, func(a, b Person) int {
        if a.Name < b.Name {
            return -1
        } else if a.Name > b.Name {
            return 1
        }
        return 0
    })
    
    fmt.Println(people)
    // [{Alice 55} {Alice 20} {Bob 24} {Gopher 13}]
    // 注意:两个 Alice 保持了原始顺序
}

Sorted

func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E

功能: 从迭代器收集值到新切片,排序后返回。

参数

  • seq iter.Seq[E] - 值的迭代器

返回值

  • []E - 排序后的切片

示例

package main

import (
    "fmt"
    "iter"
    "slices"
)

func main() {
    // 创建乱序数字迭代器
    numbers := func(yield func(int) bool) {
        for _, n := range []int{4, -2, 0, 8, -6} {
            if !yield(n) {
                return
            }
        }
    }
    
    sorted := slices.Sorted(numbers)
    fmt.Println(sorted) // [-6 -2 0 4 8]
}

SortedFunc

func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E

功能: 从迭代器收集值到新切片,使用自定义比较函数排序后返回。

参数

  • seq iter.Seq[E] - 值的迭代器
  • cmp func(E, E) int - 比较函数

返回值

  • []E - 排序后的切片

示例

package main

import (
    "fmt"
    "iter"
    "slices"
)

func main() {
    // 创建数字迭代器
    numbers := func(yield func(int) bool) {
        for _, n := range []int{4, -2, 0, 8, -6} {
            if !yield(n) {
                return
            }
        }
    }
    
    // 降序排序
    sorted := slices.SortedFunc(numbers, func(a, b int) int {
        return b - a
    })
    
    fmt.Println(sorted) // [8 4 0 -2 -6]
}

SortedStableFunc

func SortedStableFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E

功能: 从迭代器收集值到新切片,使用自定义比较函数稳定排序后返回。

参数

  • seq iter.Seq[E] - 值的迭代器
  • cmp func(E, E) int - 比较函数

返回值

  • []E - 稳定排序后的切片

示例

package main

import (
    "fmt"
    "iter"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := func(yield func(Person) bool) {
        list := []Person{
            {"Bob", 5},
            {"Gopher", 13},
            {"Alice", 20},
            {"Zac", 20},
            {"Vera", 24},
        }
        for _, p := range list {
            if !yield(p) {
                return
            }
        }
    }
    
    // 按年龄稳定排序
    sorted := slices.SortedStableFunc(people, func(a, b Person) int {
        return a.Age - b.Age
    })
    
    fmt.Println(sorted)
    // [{Bob 5} {Gopher 13} {Alice 20} {Zac 20} {Vera 24}]
    // 注意:Alice 和 Zac 年龄相同,保持了原始顺序
}

V

Values

func Values[Slice ~[]E, E any](s Slice) iter.Seq[E]

功能: 返回一个迭代器,按顺序产生切片中的元素。

参数

  • s Slice - 要遍历的切片

返回值

  • iter.Seq[E] - 产生元素值的迭代器

示例

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bob", "Vera"}
    
    for name := range slices.Values(names) {
        fmt.Println(name)
    }
}

运行结果

Alice
Bob
Vera

典型示例

示例 1:切片去重

package main

import (
    "fmt"
    "slices"
)

func removeDuplicates[T comparable](s []T) []T {
    if len(s) == 0 {
        return s
    }
    
    // 先排序
    slices.Sort(s)
    
    // 再去重
    return slices.Compact(s)
}

func main() {
    nums := []int{3, 1, 2, 3, 1, 4, 2}
    unique := removeDuplicates(nums)
    fmt.Println(unique) // [1 2 3 4]
}

示例 2:查找满足条件的元素

package main

import (
    "fmt"
    "slices"
)

func findAdults(names []string, ages []int) []string {
    var adults []string
    
    for i, age := range ages {
        if age >= 18 {
            adults = append(adults, names[i])
        }
    }
    
    return adults
}

func main() {
    names := []string{"Alice", "Bob", "Charlie"}
    ages := []int{20, 15, 25}
    
    adults := findAdults(names, ages)
    fmt.Println(adults) // [Alice Charlie]
    
    // 使用 ContainsFunc 检查是否有成年人
    hasAdult := slices.ContainsFunc(ages, func(age int) bool {
        return age >= 18
    })
    fmt.Println("Has adult:", hasAdult) // true
}

示例 3:切片转换

package main

import (
    "fmt"
    "slices"
    "strings"
)

func toUpper(names []string) []string {
    result := make([]string, len(names))
    for i, name := range names {
        result[i] = strings.ToUpper(name)
    }
    return result
}

func main() {
    names := []string{"alice", "bob", "vera"}
    upper := toUpper(names)
    fmt.Println(upper) // [ALICE BOB VERA]
}

示例 4:二分查找自定义类型

package main

import (
    "fmt"
    "slices"
)

type Product struct {
    ID    int
    Name  string
    Price float64
}

func main() {
    products := []Product{
        {1, "Apple", 1.5},
        {2, "Banana", 0.8},
        {3, "Cherry", 2.0},
    }
    
    // 按价格排序
    slices.SortFunc(products, func(a, b Product) int {
        if a.Price < b.Price {
            return -1
        } else if a.Price > b.Price {
            return 1
        }
        return 0
    })
    
    // 查找价格为 0.8 的产品
    idx, found := slices.BinarySearchFunc(products, 0.8, 
        func(p Product, price float64) int {
            if p.Price < price {
                return -1
            } else if p.Price > price {
                return 1
            }
            return 0
        })
    
    if found {
        fmt.Printf("Found: %s\n", products[idx].Name) // Found: Banana
    }
}

示例 5:批量删除元素

package main

import (
    "fmt"
    "slices"
)

func removeNegatives(nums []int) []int {
    return slices.DeleteFunc(nums, func(n int) bool {
        return n < 0
    })
}

func main() {
    nums := []int{1, -2, 3, -4, 5, -6}
    filtered := removeNegatives(nums)
    fmt.Println(filtered) // [1 3 5]
}

示例 6:切片合并

package main

import (
    "fmt"
    "slices"
)

func mergeAndSort[T cmp.Ordered](slices ...[]T) []T {
    return slices.Concat(slices...)
}

func main() {
    s1 := []int{1, 3, 5}
    s2 := []int{2, 4, 6}
    s3 := []int{7, 8, 9}
    
    merged := slices.Concat(s1, s2, s3)
    slices.Sort(merged)
    
    fmt.Println(merged) // [1 2 3 4 5 6 7 8 9]
}

示例 7:检查切片是否包含某范围

package main

import (
    "fmt"
    "slices"
)

func containsRange(nums []int, min, max int) bool {
    return slices.ContainsFunc(nums, func(n int) bool {
        return n >= min && n <= max
    })
}

func main() {
    nums := []int{1, 5, 10, 15, 20}
    
    fmt.Println(containsRange(nums, 8, 12))  // true (包含 10)
    fmt.Println(containsRange(nums, 100, 200)) // false
}

示例 8:使用迭代器

package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Alice", "Bob", "Vera"}
    
    // 正向遍历
    fmt.Println("Forward:")
    for i, name := range slices.All(names) {
        fmt.Printf("%d: %s\n", i, name)
    }
    
    // 反向遍历
    fmt.Println("\nBackward:")
    for i, name := range slices.Backward(names) {
        fmt.Printf("%d: %s\n", i, name)
    }
    
    // 仅遍历值
    fmt.Println("\nValues:")
    for name := range slices.Values(names) {
        fmt.Println(name)
    }
}

最佳实践

1. 优先使用泛型函数

// ✅ 推荐:使用 slices 包
if slices.Contains(nums, target) {
    // ...
}

// ❌ 不推荐:手动循环
found := false
for _, n := range nums {
    if n == target {
        found = true
        break
    }
}

2. 使用 DeleteFunc 代替手动过滤

// ✅ 推荐
nums = slices.DeleteFunc(nums, func(n int) bool {
    return n < 0
})

// ❌ 不推荐:手动过滤
var filtered []int
for _, n := range nums {
    if n >= 0 {
        filtered = append(filtered, n)
    }
}

3. 使用 SortFunc 进行复杂排序

// ✅ 推荐
slices.SortFunc(people, func(a, b Person) int {
    return a.Age - b.Age
})

// ❌ 不推荐:使用 sort.Slice
sort.Slice(people, func(i, j int) bool {
    return people[i].Age < people[j].Age
})

4. 使用 Clone 复制切片

// ✅ 推荐
copy := slices.Clone(original)

// ❌ 不推荐:容易出错
copy := make([]int, len(original))
copy(original, copy)

5. 批量操作优于多次单元素操作

// ✅ 推荐:一次删除多个
slices.Delete(s, i, j)

// ❌ 不推荐:逐个删除
for k := i; k < j; k++ {
    s = slices.Delete(s, i, i+1)
}

与其他包配合

与 iter 包配合

package main

import (
    "fmt"
    "iter"
    "slices"
)

func main() {
    // 创建迭代器
    numbers := func(yield func(int) bool) {
        for i := 0; i < 10; i++ {
            if !yield(i * 2) {
                return
            }
        }
    }
    
    // 收集并排序
    sorted := slices.Sorted(numbers)
    fmt.Println(sorted) // [0 2 4 6 8 10 12 14 16 18]
    
    // 使用 AppendSeq
    base := []int{-2, -1}
    extended := slices.AppendSeq(base, numbers)
    fmt.Println(extended) // [-2 -1 0 2 4 6 8 10 12 14 16 18]
}

与 cmp 包配合

package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Item struct {
    Name  string
    Value int
}

func main() {
    items := []Item{
        {"Apple", 5},
        {"Banana", 3},
        {"Cherry", 8},
    }
    
    // 使用 cmp.Compare
    slices.SortFunc(items, func(a, b Item) int {
        return cmp.Compare(a.Value, b.Value)
    })
    
    fmt.Println(items)
}

注意事项

限制

  1. Go 版本要求

    • Go 1.21+ 才支持
    • Go 1.21-1.22 为实验性
    • Go 1.23+ 已稳定
  2. 性能考虑

    • 某些操作会修改原切片
    • Delete 和 Insert 是 O(n) 操作
  3. 空切片处理

    • Max 和 Min 在空切片时会 panic
    • 大部分函数能正确处理 nil 切片

使用建议

  1. 检查切片是否为空

    if len(s) == 0 {
        // 处理空切片
        return
    }
    max := slices.Max(s)
    
  2. 理解原地修改

    // Compact、Delete 等会修改原切片
    s = slices.Compact(s) // 需要重新赋值
    
  3. 注意容量变化

    // Delete 后容量不变,长度变小
    // 使用 Clip 移除未使用的容量
    s = slices.Clip(s)
    

快速参考

函数速查表

函数功能时间复杂度
All正向迭代器O(1)
Backward反向迭代器O(1)
BinarySearch二分查找O(log n)
Chunk分块迭代O(1)
Clip移除未用容量O(1)
Clone复制切片O(n)
Collect收集迭代器O(n)
Compact去重O(n)
Compare比较切片O(n)
Concat连接切片O(n)
Contains包含检查O(n)
Delete删除元素O(n-i)
Equal相等检查O(n)
Grow扩展容量O(n)
Index查找索引O(n)
Insert插入元素O(n)
IsSorted检查排序O(n)
Max/Min最值O(n)
Repeat重复切片O(n)
Replace替换元素O(n)
Reverse反转切片O(n)
Sort排序O(n log n)
Values值迭代器O(1)

编译要求

# Go 1.21+
go version

# 导入包
import "slices"

常见模式

// 1. 检查包含
if slices.Contains(s, v) { }

// 2. 查找索引
if idx := slices.Index(s, v); idx >= 0 { }

// 3. 排序
slices.Sort(s)

// 4. 去重
slices.Sort(s)
s = slices.Compact(s)

// 5. 复制
copy := slices.Clone(s)

// 6. 删除
s = slices.DeleteFunc(s, predicate)

// 7. 最值
max := slices.Max(s)
min := slices.Min(s)

总结

slices 包是 Go 1.21+ 提供的切片操作工具库,使用泛型实现,适用于任意类型的切片。

核心优势

  • ✅ 泛型实现,类型安全
  • ✅ 丰富的操作函数
  • ✅ 代码简洁易读
  • ✅ 性能优化
  • ✅ 支持迭代器

重要限制

  • ⚠️ 需要 Go 1.21+
  • ⚠️ Max/Min 在空切片时 panic
  • ⚠️ 某些操作会修改原切片

主要用途

  • 切片比较和查找
  • 切片修改(插入、删除、替换)
  • 排序和检查排序
  • 去重和压缩
  • 最值查找
  • 迭代器操作

使用建议

  1. 优先使用泛型函数代替手动循环
  2. 理解哪些函数会修改原切片
  3. 注意空切片的特殊情况
  4. 批量操作优于多次单元素操作
  5. 使用迭代器简化遍历