Go1.21新增了slices包,该包提供了slice相关的工具函数。

相关issue: https://github.com/golang/go/issues/57433

slices pkg中提供了部分相关的example。

二分查找

可参考

压缩

可参考

需要注意的是,这里的压缩是针对相邻的元素,如果相等的元素间隔排列,则不会被压缩。

    fmt.Println("slices.Compact")
    seq := []int{0, 1, 1, 2, 1, 3, 5, 8}
    fmt.Printf("%v len(seq)=%d\n", seq, len(seq))
    seq = slices.Compact(seq)
    fmt.Printf("%v len(seq)=%d\n", seq, len(seq))
    // output
    // [0 1 1 2 1 3 5 8] len(seq)=8
    // [0 1 2 1 3 5 8] len(seq)=7

比较

可参考

删除

可参考

查找位置

可参考

是否已经排序

可参考

需要注意的是,这里都只是检查是否按照升序进行排序。如果是降序或者无序,则返回false。

    fmt.Println(slices.IsSorted([]int{0, 1, 2})) // true
    fmt.Println(slices.IsSorted([]int{0, 2, 1})) // false
    fmt.Println(slices.IsSorted([]int{2, 1, 0})) // false

最大值,最小值

可参考

需要注意的是,如果slice为空,则会panic。

    numbers := []int{}
    slices.Max(numbers) // panic: slices.Max: empty list

是否包含

Contains函数可以用来判断slice中是否包含某个元素,内部实现用了Index函数。

    s := []string{"Apple", "Banana", "Orange"}
    fmt.Println("Have Apple?", slices.Contains(s, "Apple"))

替换

可参考

    originalNames := []string{"Alice", "Bob", "Vera", "Zac"}
    fmt.Printf("%v\n", originalNames)

    // 替换[1, 3) 之间的元素,替换的元素个数没必要和被替换的元素个数相同
    names := slices.Replace(originalNames, 1, 3, "Bill", "Billie", "Cat")
    fmt.Printf("%v\n", names)

    names = slices.Replace(originalNames, 0, 0, "Bill", "Billie", "Cat")
    fmt.Printf("%v\n", names)

逆序

可参考

排序

可参考

SortStableFunc内部使用了插入排序,而SortFunc内部使用了快速排序(其实是Pattern-defeating quicksort)。

缩容

Clip函数可以从slice中移除不必要的容量。这可以在运行时在slices占用过多内存的时候,释放内存。

    s := make([]int, 0, 10)
    s = append(s, 1, 2, 3)
    fmt.Printf("%v len=%d cap=%d %p\n", s, len(s), cap(s), s)
    // output
    // [1 2 3] len=3 cap=10 0xc0000b4050
    afterClip := slices.Clip(s)
    fmt.Printf("%v len=%d cap=%d %p\n", afterClip, len(afterClip), cap(afterClip), afterClip)
    // output
    // [1 2 3] len=3 cap=3 0xc0000b4050

本质上该函数的工作就是s[:len(s):len(s)]

扩容

Grow函数可以扩容slice的容量,如果slice的容量不够,那么就会扩容。

    s := make([]int, 0, 10)
    s = append(s, 1, 2, 3)
    fmt.Printf("%v len=%d cap=%d %p\n", s, len(s), cap(s), s)
    // output
    // [1 2 3] len=3 cap=10 0xc000120050
    afterGrow := slices.Grow(s, 20)
    fmt.Printf("%v len=%d cap=%d %p\n", afterGrow, len(afterGrow), cap(afterGrow), afterGrow)
    // output
    // [1 2 3] len=3 cap=24 0xc00012a000

需要注意的是,如果Grow的第二个参数为负数或过大无法分配内存的时候,就会panic。

克隆

Clone函数可以克隆一个slice,需要注意的是它是浅拷贝。

    type Person struct {
        Name string
    }
    people := []Person{
        {Name: "bob"},
        {Name: "alice"},
    }
    clonePeople := slices.Clone(people)
    fmt.Printf("clonePeople %v %p\n", clonePeople, clonePeople)
    // output
    // [{bob} {alice}] 0xc0000b40e0
    clonePeople[0].Name = "Bob"
    fmt.Printf("clonePeople %v %p\n", clonePeople, clonePeople)
    // output
    // [{Bob} {alice}] 0xc0000b40e0
    fmt.Printf("people %v %p\n", people, people)
    // output
    // [{Bob} {alice}] 0xc0000b40e0