Package slices defines various functions useful with slices of any type. This package provides generic slice operations that work with any element type through Go's type parameters. It includes functions for searching, sorting, comparing, modifying, and querying slices.
Note: This package is largely superseded by Go's built-in slices package (available in Go 1.21+), which contains similar functionality. The experimental package remains available for backward compatibility and for users on older Go versions.
go get golang.org/x/exp/slicesimport (
"golang.org/x/exp/slices"
"cmp"
)The package uses Go 1.18+ generics. The cmp package is used for comparison functions in generic contexts.
package main
import (
"fmt"
"golang.org/x/exp/slices"
)
func main() {
// Clone a slice
original := []int{1, 2, 3, 4, 5}
cloned := slices.Clone(original)
// Search in sorted slice
sorted := []int{1, 3, 5, 7, 9}
idx, found := slices.BinarySearch(sorted, 5)
fmt.Println(found) // true
// Check if slice contains value
contains := slices.Contains([]string{"a", "b", "c"}, "b")
fmt.Println(contains) // true
// Sort a slice
numbers := []int{5, 2, 8, 1, 9}
slices.Sort(numbers)
fmt.Println(numbers) // [1 2 5 8 9]
}Functions for searching elements in slices.
Searches for a target value in a sorted slice using binary search.
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool)Returns the position where target is found (or would be inserted), and a boolean indicating whether the target was actually found. The slice must be sorted in ascending order.
Example:
sorted := []int{1, 3, 5, 7, 9}
idx, found := slices.BinarySearch(sorted, 5)
// idx = 2, found = true
idx, found = slices.BinarySearch(sorted, 4)
// idx = 2, found = false (4 would be inserted at position 2)Like BinarySearch but uses a custom comparison function.
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool)The comparison function should return 0 if elements match, a negative number if the slice element precedes the target, or a positive number if it follows.
Example:
type Person struct {
Age int
Name string
}
people := []Person{{Age: 25, Name: "Alice"}, {Age: 35, Name: "Bob"}}
idx, found := slices.BinarySearchFunc(people, 30, func(p Person, target int) int {
if p.Age < target {
return -1
}
if p.Age > target {
return 1
}
return 0
})Functions for sorting slices.
Sorts a slice of any ordered type in ascending order.
func Sort[S ~[]E, E cmp.Ordered](x S)Modifies the slice in place. NaNs are ordered before other floating-point values.
Example:
numbers := []int{5, 2, 8, 1, 9}
slices.Sort(numbers)
// numbers is now [1 2 5 8 9]Sorts a slice using a custom comparison function.
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int)The comparison function should return a negative number when a < b, a positive number when a > b, and zero when a == b. This sort is not guaranteed to be stable.
Example:
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
}
slices.SortFunc(people, func(a, b Person) int {
if a.Age < b.Age {
return -1
}
if a.Age > b.Age {
return 1
}
return 0
})Sorts a slice while keeping the original order of equal elements (stable sort).
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int)Behaves like SortFunc but preserves the order of elements that compare equal.
Functions for comparing slices and their elements.
Compares two slices element-by-element using natural ordering.
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) intReturns 0 if slices are equal, -1 if s1 < s2, and 1 if s1 > s2. If one slice is a prefix of the other, the shorter slice is considered less than the longer one.
Example:
result := slices.Compare([]int{1, 2}, []int{1, 3})
// result = -1 (first slice is less)
result = slices.Compare([]int{1, 2}, []int{1, 2})
// result = 0 (slices are equal)Compares two slices using a custom comparison function.
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) intSimilar to Compare but allows comparing slices of different element types.
Reports whether two slices are equal (same length and all elements equal).
func Equal[S ~[]E, E comparable](s1, s2 S) boolReturns false if lengths differ. Floating-point NaNs are not considered equal.
Example:
equal := slices.Equal([]int{1, 2, 3}, []int{1, 2, 3})
// equal = true
equal = slices.Equal([]int{1, 2}, []int{1, 2, 3})
// equal = falseCompares two slices using a custom equality function.
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) boolReturns false if lengths differ or if any elements don't satisfy the equality function.
Functions for finding elements in slices.
Reports whether a value is present in the slice.
func Contains[S ~[]E, E comparable](s S, v E) boolReturns true if the value is found, false otherwise.
Example:
contains := slices.Contains([]string{"apple", "banana", "orange"}, "banana")
// contains = trueReports whether at least one element satisfies a predicate function.
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) boolExample:
hasEven := slices.ContainsFunc([]int{1, 3, 5, 7, 8}, func(v int) bool {
return v%2 == 0
})
// hasEven = trueReturns the index of the first occurrence of a value, or -1 if not found.
func Index[S ~[]E, E comparable](s S, v E) intExample:
idx := slices.Index([]int{10, 20, 30, 20, 40}, 20)
// idx = 1 (first occurrence)
idx = slices.Index([]int{10, 20, 30}, 50)
// idx = -1 (not found)Returns the first index where a predicate function returns true, or -1 if none do.
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) intExample:
idx := slices.IndexFunc([]int{2, 4, 6, 7, 8}, func(v int) bool {
return v%2 == 1
})
// idx = 3 (7 is odd)Functions for modifying slice contents.
Returns a shallow copy of the slice.
func Clone[S ~[]E, E any](s S) SElements are copied by assignment. The capacity of the clone is equal to its length.
Example:
original := []int{1, 2, 3, 4, 5}
cloned := slices.Clone(original)
cloned[0] = 999
// original[0] is still 1Removes unused capacity from the slice, returning s[:len(s):len(s)].
func Clip[S ~[]E, E any](s S) SReduces the slice's capacity to match its length. Useful for releasing excess allocated memory.
Example:
s := make([]int, 3, 10) // length 3, capacity 10
s = slices.Clip(s)
// Now length and capacity are both 3Removes elements from the slice, returning the modified slice.
func Delete[S ~[]E, E any](s S, i, j int) SRemoves elements from index i to j (s[i:j]). Elements at s[i:] are shifted up. Panics if j > len(s) or if s[i:j] is invalid. Zeroes elements s[len(s)-(j-i):len(s)].
Example:
s := []int{1, 2, 3, 4, 5}
s = slices.Delete(s, 1, 3) // Remove indices 1 and 2
// s is now [1 4 5]Removes all elements for which a function returns true.
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) SReturns the modified slice. Zeroes elements between the new length and original length.
Example:
s := []int{1, 2, 3, 4, 5, 6}
s = slices.DeleteFunc(s, func(v int) bool {
return v%2 == 0 // Remove even numbers
})
// s is now [1 3 5]Inserts values into the slice at a specified index.
func Insert[S ~[]E, E any](s S, i int, v ...E) SElements at s[i:] are shifted up to make room. In the returned slice r, r[i] == v[0]. Panics if i is out of range. This is O(len(s) + len(v)).
Example:
s := []int{1, 2, 5}
s = slices.Insert(s, 2, 3, 4)
// s is now [1 2 3 4 5]Replaces elements from index i to j with new values.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) SReplaces s[i:j] with the given values. Panics if s[i:j] is invalid. If len(v) < (j-i), zeroes elements between the new and original lengths.
Example:
s := []int{1, 2, 3, 4, 5}
s = slices.Replace(s, 1, 4, 20, 30)
// s is now [1 20 30 5]Reverses the elements of the slice in place.
func Reverse[S ~[]E, E any](s S)Example:
s := []int{1, 2, 3, 4, 5}
slices.Reverse(s)
// s is now [5 4 3 2 1]Replaces consecutive runs of equal elements with a single copy.
func Compact[S ~[]E, E comparable](s S) SLike the Unix uniq command. Modifies the slice and returns it with potentially smaller length. Zeroes elements between new and original lengths.
Example:
s := []int{1, 1, 2, 2, 2, 3, 3, 4}
s = slices.Compact(s)
// s is now [1 2 3 4]Like Compact but uses a custom equality function.
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) SKeeps the first element of each run of equal elements.
Example:
type Person struct {
Name string
ID int
}
s := []Person{
{"Alice", 1}, {"Alice", 1},
{"Bob", 2}, {"Bob", 2}, {"Bob", 2},
}
s = slices.CompactFunc(s, func(a, b Person) bool {
return a.ID == b.ID
})
// s now has only 2 elements (one Alice, one Bob)Functions for finding minimum and maximum values.
Returns the maximal value in the slice.
func Max[S ~[]E, E cmp.Ordered](x S) EPanics if the slice is empty. For floating-point numbers, propagates NaNs (any NaN forces the output to be NaN).
Example:
max := slices.Max([]int{3, 1, 4, 1, 5, 9, 2, 6})
// max = 9Returns the maximal value using a custom comparison function.
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) EPanics if the slice is empty. If multiple elements are maximal, returns the first one.
Returns the minimal value in the slice.
func Min[S ~[]E, E cmp.Ordered](x S) EPanics if the slice is empty. For floating-point numbers, propagates NaNs.
Example:
min := slices.Min([]int{3, 1, 4, 1, 5, 9, 2, 6})
// min = 1Returns the minimal value using a custom comparison function.
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) EPanics if the slice is empty. If multiple elements are minimal, returns the first one.
Functions for managing slice capacity.
Increases the slice's capacity to guarantee space for more elements.
func Grow[S ~[]E, E any](s S, n int) SAfter Grow(n), at least n elements can be appended to the slice without another allocation. Panics if n is negative or too large to allocate memory.
Example:
s := []int{1, 2, 3}
s = slices.Grow(s, 5)
// Now at least 5 more elements can be appended without reallocation
s = append(s, 4, 5, 6, 7, 8)Functions for checking if slices are sorted.
Reports whether a slice is sorted in ascending order.
func IsSorted[S ~[]E, E cmp.Ordered](x S) boolExample:
sorted := slices.IsSorted([]int{1, 2, 3, 4, 5})
// sorted = true
sorted = slices.IsSorted([]int{1, 3, 2, 4, 5})
// sorted = falseReports whether a slice is sorted using a custom comparison function.
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) boolThe package uses Go 1.18+ generic constraints:
// Constraints from cmp package used by this package
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}S ~[]E - Slice type constraint (S is a type with underlying type []E)E cmp.Ordered - Ordered types (integers, floats, strings)E comparable - Comparable types (can be compared with ==)E any - Any type (used with custom comparison functions)Generics Requirement: Requires Go 1.18 or later for full support.
In-Place Modifications: Many functions (Sort, Reverse, Delete, etc.) modify the slice in place. However, they may return a different slice header due to the way Go handles slice resizing.
Panics: Some functions panic on invalid input:
Memory Cleanup: Functions like Compact, Delete, and DeleteFunc zero out elements between the new length and original length to allow garbage collection.
Stability: SortFunc is not stable, but SortStableFunc maintains the original order of equal elements.
NaN Handling: Max and Min propagate NaNs in floating-point slices. Sort places NaNs before other values.
Comparison Functions: When using custom comparison functions, they must implement strict weak ordering. Return -1 for a < b, 0 for a == b or uncomparable, and 1 for a > b.
As of Go 1.21, the built-in slices package provides equivalent functionality without requiring external dependencies. For new projects using Go 1.21+, prefer using the built-in slices package from the standard library.