How to Sort a Slice in Go 1.21: The Modern Generic Approach

Use the slices.Sort function for ordered types and slices.SortFunc with cmp.Compare for custom ordering logic, both introduced in the Go 1.21 standard library.

The JetBrains/go-modern-guidelines repository establishes that code targeting Go 1.21+ should migrate from the legacy sort package to the generic slices package. This shift eliminates reflection overhead and provides compile-time type safety for sorting operations.

Sorting Ordered Types with slices.Sort

For slices of ordered types—including int, float64, string, and their aliases—use slices.Sort. This replaces the type-specific functions sort.Ints, sort.Strings, and sort.Float64s with a single generic implementation.

According to internal/guidelines/guidelines.json at line 828, the guideline states: "Use slices.Sort for slices of ordered values." The function accepts any type satisfying the constraints.Ordered interface, unifying sorting syntax across primitive types.

package main

import (
    "fmt"
    "slices"
)

func main() {
    // Integer sorting
    ints := []int{5, 2, 9, 1}
    slices.Sort(ints)
    fmt.Println(ints) // [1 2 5 9]

    // String sorting
    words := []string{"banana", "apple", "cherry"}
    slices.Sort(words)
    fmt.Println(words) // [apple banana cherry]
}

Custom Comparators with slices.SortFunc

When sorting by custom criteria or complex structs, use slices.SortFunc combined with cmp.Compare. This pattern supersedes sort.Slice, which required fragile index-based closures.

The guideline at line 808 of internal/guidelines/guidelines.json recommends: "Use slices.SortFunc with cmp.Compare instead of sort.Slice for typed comparisons." The comparator function receives the actual elements rather than indices, preventing off-by-one errors and eliminating type assertions.

package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 35},
    }

    // Sort by Age ascending
    slices.SortFunc(people, func(a, b Person) int {
        return cmp.Compare(a.Age, b.Age)
    })
    
    fmt.Println(people) // [{Bob 25} {Alice 30} {Carol 35}]
}

The cmp.Compare helper returns -1, 0, or 1 based on the comparison, making the sort order explicit and consistent across your codebase.

Source Code Guidelines

The JetBrains/go-modern-guidelines project encodes these rules in internal/guidelines/guidelines.json, which is loaded at compile-time by internal/guidelines/guidelines.go. The helper functions ListText and ExplainText expose these guidelines to CLI tools, ensuring the recommendations remain synchronized with the repository's analysis logic.

Unlike the pre-generics sort package that relied on interface{} and reflection, the slices implementation generates optimized code for your specific type at compile time.

Summary

  • Replace sort.Ints and sort.Strings with slices.Sort for primitive types.
  • Replace sort.Slice with slices.SortFunc and cmp.Compare for custom ordering.
  • Import slices from the standard library (available since Go 1.21) to avoid third-party dependencies.
  • Reference internal/guidelines/guidelines.json in the JetBrains repository for authoritative guidance on modern sorting patterns.

Frequently Asked Questions

What replaced sort.Slice in Go 1.21?

slices.SortFunc replaced sort.Slice for custom sorting logic. Where sort.Slice required a function comparing indices (func(i, j int) bool), slices.SortFunc uses typed element comparison (func(a, b T) int), eliminating index boundary errors and reflection overhead as documented in the JetBrains guidelines.

Do I need to import constraints to use slices.Sort?

No. While slices.Sort internally requires types satisfying constraints.Ordered, you do not need to import golang.org/x/exp/constraints. Simply pass slices of built-in ordered types (int, float64, string) directly to the function.

How do I sort a slice in descending order using modern Go?

Use slices.SortFunc with an inverted comparator. Swap the arguments passed to cmp.Compare (e.g., return cmp.Compare(b.Age, a.Age) for descending age sort), or sort ascending then call slices.Reverse on the slice.

Is slices.Sort faster than the old sort.Ints?

Yes. The slices.Sort function avoids the interface conversion and reflection costs present in sort.Ints. By using generics, the compiler generates monomorphized sorting code specific to your element type, resulting in better CPU cache utilization and fewer allocations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →