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 slices package needs Go 1.21+. If go.mod says an older version, run go mod edit -go=1.21 and go mod tidy.

At a glance

Need to…Use
Check if a value is in the sliceContains, ContainsFunc
Find the index of a valueIndex, IndexFunc
SortSort, SortFunc, SortStableFunc
Binary search (sorted slice)BinarySearch, BinarySearchFunc
Reverse in placeReverse
Add/remove elementsInsert, Delete, Replace
Compare two slicesEqual, Compare
Find min/maxMin, Max, MinFunc, MaxFunc
Copy a sliceClone
Join several slicesConcat
Remove consecutive duplicatesCompact

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 a should come before b
  • zero if they’re equal
  • a positive number if a should come after b

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)

Compact is 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 := a does NOT copy. Both variables point to the same underlying array. Use slices.Clone (or make + 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) or BinarySearch (sorted)
  • Sorting structs?SortFunc, return a.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), never b := a
  • Removing all duplicates?Sort then Compact

Common mistakes

  • Calling modify functions without assigning backslices.Delete(nums, 1, 3) does NOT modify nums in the obvious way; you must reassign.
  • b := a thinking it copies — it copies the slice header but not the underlying array.
  • Compact thinking it removes all duplicates — it only removes consecutive ones.
  • Min/Max on an empty slice — panics. Check length first.
  • BinarySearch on an unsorted slice — returns garbage. Sort first.
  • Using sort.Slice in new codeslices.SortFunc is the modern equivalent and reads better.
Toggle theme (T)