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)
}
注意事项
限制
-
Go 版本要求:
- Go 1.21+ 才支持
- Go 1.21-1.22 为实验性
- Go 1.23+ 已稳定
-
性能考虑:
- 某些操作会修改原切片
- Delete 和 Insert 是 O(n) 操作
-
空切片处理:
- Max 和 Min 在空切片时会 panic
- 大部分函数能正确处理 nil 切片
使用建议
-
检查切片是否为空:
if len(s) == 0 { // 处理空切片 return } max := slices.Max(s) -
理解原地修改:
// Compact、Delete 等会修改原切片 s = slices.Compact(s) // 需要重新赋值 -
注意容量变化:
// 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
- ⚠️ 某些操作会修改原切片
主要用途:
- 切片比较和查找
- 切片修改(插入、删除、替换)
- 排序和检查排序
- 去重和压缩
- 最值查找
- 迭代器操作
使用建议:
- 优先使用泛型函数代替手动循环
- 理解哪些函数会修改原切片
- 注意空切片的特殊情况
- 批量操作优于多次单元素操作
- 使用迭代器简化遍历