The slices package (added in Go 1.21) is the modern standard library for working with slices — sorting, searching, comparing, modifying. Before 1.21, you’d write loops or reach for the older sort package. Now most of it is a one-liner.
Import it:
import "slices"
Go version: The
slicespackage needs Go 1.21+. Ifgo.modsays an older version, rungo mod edit -go=1.21andgo mod tidy.
At a glance
| Need to… | Use |
|---|---|
| Check if a value is in the slice | Contains, ContainsFunc |
| Find the index of a value | Index, IndexFunc |
| Sort | Sort, SortFunc, SortStableFunc |
| Binary search (sorted slice) | BinarySearch, BinarySearchFunc |
| Reverse in place | Reverse |
| Add/remove elements | Insert, Delete, Replace |
| Compare two slices | Equal, Compare |
| Find min/max | Min, Max, MinFunc, MaxFunc |
| Copy a slice | Clone |
| Join several slices | Concat |
| Remove consecutive duplicates | Compact |
The rest of this page covers each group with examples.
Searching
Contains and Index
nums := []int{1, 2, 3, 4, 5}
slices.Contains(nums, 3) // true
slices.Contains(nums, 99) // false
slices.Index(nums, 3) // 2
slices.Index(nums, 99) // -1
ContainsFunc and IndexFunc — custom matching
When the value isn’t directly comparable (a struct field, a partial match, etc.):
words := []string{"apple", "banana", "cherry"}
slices.ContainsFunc(words, func(s string) bool {
return strings.HasPrefix(s, "b")
}) // true
slices.IndexFunc(words, func(s string) bool {
return len(s) > 5
}) // 1 (banana)
BinarySearch — fast lookup in sorted slices
Returns the index where the value is (or where it would be inserted) and a bool saying whether it was actually found.
sorted := []int{1, 3, 5, 7, 9}
i, found := slices.BinarySearch(sorted, 5) // i=2, found=true
i, found = slices.BinarySearch(sorted, 6) // i=3, found=false (would go between 5 and 7)
The slice must be sorted. If it isn’t, the result is meaningless.
Sorting
Sort — for comparable types
Sorts in place. Works on any “ordered” type: numbers, strings, bytes.
nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.Sort(nums)
// nums is now [1, 1, 2, 3, 4, 5, 6, 9]
words := []string{"banana", "apple", "cherry"}
slices.Sort(words)
// words is now ["apple", "banana", "cherry"]
SortFunc — custom comparator
Use this when sorting structs, or sorting in a non-default order (descending, by length, etc.).
The compare function returns:
- a negative number if
ashould come beforeb - zero if they’re equal
- a positive number if
ashould come afterb
The easy way: subtract.
type Person struct {
Name string
Age int
}
people := []Person{
{"Charlie", 25},
{"Alice", 30},
{"Bob", 22},
}
// Sort by age (ascending)
slices.SortFunc(people, func(a, b Person) int {
return a.Age - b.Age
})
// Sort by name (ascending)
slices.SortFunc(people, func(a, b Person) int {
return strings.Compare(a.Name, b.Name)
})
// Sort by age (descending) — flip the sign
slices.SortFunc(people, func(a, b Person) int {
return b.Age - a.Age
})
SortStableFunc — preserve order of equal elements
If two elements compare equal, SortStableFunc keeps them in their original relative order. SortFunc doesn’t guarantee that.
// If you sort by age and two people are 30, stable sort keeps
// whichever came first in the input first.
slices.SortStableFunc(people, func(a, b Person) int {
return a.Age - b.Age
})
IsSorted and IsSortedFunc
slices.IsSorted([]int{1, 2, 3}) // true
slices.IsSorted([]int{1, 3, 2}) // false
Modifying
The functions in this section return a new slice that may share the same underlying array as the input. Always assign the result back:
nums = slices.Delete(nums, 1, 3) // ✅ keep the new header
slices.Delete(nums, 1, 3) // ❌ result discarded, original may still be wrong
Delete — remove a range
nums := []int{1, 2, 3, 4, 5}
nums = slices.Delete(nums, 1, 3) // remove indices 1..2 (3 is exclusive)
// nums = [1, 4, 5]
Insert — add at a position
nums := []int{1, 2, 5}
nums = slices.Insert(nums, 2, 3, 4) // insert 3, 4 at index 2
// nums = [1, 2, 3, 4, 5]
Replace — swap a range for new values
nums := []int{1, 2, 3, 4, 5}
nums = slices.Replace(nums, 1, 4, 9, 9) // replace indices 1..3 with 9, 9
// nums = [1, 9, 9, 5]
Reverse — flip in place
nums := []int{1, 2, 3, 4, 5}
slices.Reverse(nums)
// nums = [5, 4, 3, 2, 1]
Compact — remove consecutive duplicates
nums := []int{1, 1, 2, 3, 3, 3, 4, 1}
nums = slices.Compact(nums)
// nums = [1, 2, 3, 4, 1] (note: the trailing 1 stays — only *consecutive* dupes are removed)
Compactis not the same as “remove all duplicates”. It only removes consecutive duplicates. To remove all duplicates, sort first:slices.Sort(nums) nums = slices.Compact(nums)
Comparing
Equal — element-by-element equality
slices.Equal([]int{1, 2, 3}, []int{1, 2, 3}) // true
slices.Equal([]int{1, 2, 3}, []int{1, 2}) // false
Compare — lexicographic order
Returns -1, 0, or 1 like strings.Compare:
slices.Compare([]int{1, 2}, []int{1, 3}) // -1
slices.Compare([]int{1, 2}, []int{1, 2}) // 0
slices.Compare([]int{1, 3}, []int{1, 2}) // 1
Min, Max
nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.Min(nums) // 1
slices.Max(nums) // 9
Panics on empty slices. Check length first if that’s possible.
With a custom comparator:
slices.MinFunc(people, func(a, b Person) int {
return a.Age - b.Age
}) // youngest person
Cloning and joining
Clone — copy a slice
a := []int{1, 2, 3}
b := slices.Clone(a)
b[0] = 99
// a is still [1, 2, 3]
b := adoes NOT copy. Both variables point to the same underlying array. Useslices.Clone(ormake+copy) when you need an independent copy.
Concat — join multiple slices
a := []int{1, 2}
b := []int{3, 4}
c := []int{5, 6}
combined := slices.Concat(a, b, c) // [1, 2, 3, 4, 5, 6]
Old vs new — sort.Slice vs slices.SortFunc
For interviews, you should recognize both styles.
// Old way (pre-1.21) — still works, still in widespread use
sort.Slice(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
// New way (1.21+)
slices.SortFunc(people, func(a, b Person) int {
return a.Age - b.Age
})
Differences:
- Old:
func(i, j int) bool— you index into the slice yourself - New:
func(a, b T) int— you get the values directly, return a three-way comparison
The new API is shorter, type-safe, and avoids a class of bugs from indexing.
Common interview patterns
Remove all values equal to X
nums := []int{1, 2, 3, 2, 4, 2, 5}
nums = slices.DeleteFunc(nums, func(n int) bool {
return n == 2
})
// nums = [1, 3, 4, 5]
Remove duplicates from a slice
slices.Sort(nums)
nums = slices.Compact(nums)
Sort strings by length, then alphabetically
words := []string{"go", "rust", "c", "python", "java"}
slices.SortFunc(words, func(a, b string) int {
if len(a) != len(b) {
return len(a) - len(b)
}
return strings.Compare(a, b)
})
// ["c", "go", "java", "rust", "python"]
Find the top-3 largest numbers
nums := []int{5, 1, 8, 3, 9, 2, 7}
sorted := slices.Clone(nums) // don't mutate the original
slices.Sort(sorted)
slices.Reverse(sorted)
top3 := sorted[:3] // [9, 8, 7]
Check if two slices contain the same elements (regardless of order)
func sameElements(a, b []int) bool {
if len(a) != len(b) {
return false
}
ac := slices.Clone(a)
bc := slices.Clone(b)
slices.Sort(ac)
slices.Sort(bc)
return slices.Equal(ac, bc)
}
Quick rules of thumb
- Need to know if X is in the slice? →
Contains(linear) orBinarySearch(sorted) - Sorting structs? →
SortFunc, returna.Field - b.Field - Descending sort? → Flip:
b.Field - a.Field - Modifying a slice? → Always assign the result back:
nums = slices.Delete(nums, ...) - Need an independent copy? →
slices.Clone(s), neverb := a - Removing all duplicates? →
SortthenCompact
Common mistakes
- Calling modify functions without assigning back —
slices.Delete(nums, 1, 3)does NOT modifynumsin the obvious way; you must reassign. b := athinking it copies — it copies the slice header but not the underlying array.Compactthinking it removes all duplicates — it only removes consecutive ones.Min/Maxon an empty slice — panics. Check length first.BinarySearchon an unsorted slice — returns garbage. Sort first.- Using
sort.Slicein new code —slices.SortFuncis the modern equivalent and reads better.