skip to content

What does slices.Sort do to a slice, and which element types can it sort?

level: juniorimportance: must knowfreq 62%

answer

  1. it sorts where it stands
  2. no callback, no interface needed
  3. only types the < operator accepts
  4. ascending, in place, returns nothing
  5. ties may come out in any order

basics

~20 s

slices.Sort reorders a slice in place into ascending order and returns nothing. It is generic over element types that support the less-than operator - integers, floats and strings - so no comparison callback or interface implementation is needed.

solid answer

~40 s

`slices.Sort(x)` sorts `x` in ascending order **in place**: it returns nothing, and the caller's slice - and any other slice sharing that backing array - now sees the new order. Its element type is constrained to `cmp.Ordered`, the set of types the `<` operator works on: all integer kinds, both float kinds and `string`. So `slices.Sort` covers `[]int`, `[]string`, `[]float64` and named types with those underlying types, and nothing else; a slice of structs needs `slices.SortFunc` with an explicit comparison function. The sort is not guaranteed to be stable - there is no `slices.SortStable` for ordered elements, because two equal ordered values are indistinguishable anyway; stability is only offered as `slices.SortStableFunc`, where the payload around the key can differ. `slices` arrived in the standard library in Go 1.21.

code

go · 7 lines
go
xs := []int{3, 1, 2}
slices.Sort(xs)
fmt.Println(xs) // [1 2 3]

names := []string{"cow", "ant", "bee"}
slices.Sort(names)
fmt.Println(names) // [ant bee cow]

go deeper

for a junior

Be ready to say it sorts ascending in place, returns nothing, and works on slices of integers, floats or strings. Know that a slice of structs needs slices.SortFunc instead.

for a middle

Explain why the element type is constrained rather than any, what in-place means for a slice parameter that shares the caller's backing array, and why stability is offered only in the SortStableFunc form.

for a senior

Show the judgment about mutation: a helper that sorts a slice it was given has changed its caller's data. Say when you would sort a copy, and when slices.Min or slices.Max answers the question without sorting at all.

for a principal

Frame it as an API convention: whether functions in your codebase are allowed to reorder slices they receive, and how that expectation is documented, is a house rule worth setting once rather than debating per review.

## What the function is `slices.Sort` is the one-line way to sort a slice of ordinary values in Go: ```go xs := []int{3, 1, 2} slices.Sort(xs) // xs is now [1 2 3] ``` Its declaration is generic: ```go func Sort[S ~[]E, E cmp.Ordered](x S) ``` Three things are worth reading out of that signature. ### 1. It sorts in place and returns nothing There is no return value to assign. The elements of the slice you passed are rearranged where they sit, in the array that backs the slice. That has a consequence beginners routinely miss: **the caller's ordering is gone**, and it is gone for every other slice that shares the same backing array. If a function receives a `[]string` parameter and calls `slices.Sort` on it, the caller's slice is reordered too - a slice parameter is a view onto the caller's array, not a copy of the data. Sorting is therefore a mutation of shared state, and a function that does it should say so in its name or its doc comment. If the original order still matters somewhere, the caller must be working on its own copy of the elements before the sort happens. ### 2. The element type must be an ordered type `E cmp.Ordered` constrains the element type to the types on which the `<` operator is defined: every signed and unsigned integer kind, `float32`/`float64`, and `string`, plus any named type whose underlying type is one of those. That is exactly what lets the function do its job with no callback: it can compare two elements itself. So these compile: ```go slices.Sort([]int{3, 1, 2}) slices.Sort([]string{"cow", "ant", "bee"}) ``` and this does not: ```go type user struct { Name string Age int } slices.Sort([]user{...}) // compile error: user does not satisfy cmp.Ordered ``` A slice of structs, a slice of pointers, a slice of slices - none of them are ordered types, and for those you call `slices.SortFunc` and supply a comparison function that returns a negative, zero or positive `int`. The compile error is a feature: the mistake is caught at build time rather than at run time. Strings sort **bytewise**, in code-point order for valid UTF-8: `"Zebra"` sorts before `"apple"` because uppercase letters have smaller byte values. Case-insensitive or locale-aware ordering is a `SortFunc` job, not something `slices.Sort` will do for you. Floats containing NaN are the other rough edge - NaN compares false against everything, so a slice containing NaN has no meaningful ascending order. ### 3. It is not a stable sort The package promises no stability for `slices.Sort` - the doc comment is silent on it and the implementation is an unstable pdqsort, while the explicit "This sort is not guaranteed to be stable" line is on `slices.SortFunc` - so the sort is not stable: elements the ordering treats as equal may come out in any relative order. For a `[]int` or a `[]string` that is unobservable, since two equal ints are the same value - and that is precisely why the package offers no `SortStable` for ordered elements. The moment equal keys hang off distinguishable payloads (two records with the same age but different names), stability becomes observable, and the package's answer is `slices.SortStableFunc`, which pairs a comparison function with a stability guarantee at some extra cost. ### How it relates to the older API Before Go 1.21 there was no generic `slices` package in the standard library, and sorting a `[]int` meant `sort.Ints` or writing a comparison by hand. `slices.Sort` is the modern default for new code: shorter, type-checked, and with no reflection in the hot path. `sort.Ints`, `sort.Strings` and `sort.Float64s` still exist and still work, but the generic call is what a reviewer expects to see today. ### The companions you get for free `slices.IsSorted(x)` reports whether a slice is already in ascending order - useful as a cheap precondition check before a binary search, and useful in tests. `slices.Min` and `slices.Max` answer the single-element questions without sorting at all, in one linear pass, which is the right call when you only need the extreme value: sorting to find a minimum is O(n log n) work for an O(n) question.

  • Does slices.Sort hand you back a sorted copy, and what happens to the order the caller had?
    No - it returns nothing and rearranges the elements in place. A slice argument is a view onto the caller's backing array, so the caller, and any other slice over that same array, sees the new order. Sorting a slice you were handed is a visible mutation of someone else's data, and a function that does it should advertise that in its name or doc comment.
  • Why can slices.Sort not sort a slice of structs?
    Its element type is constrained to `cmp.Ordered` - the types the `<` operator is defined on: integers, floats and strings. A struct supports no ordering the compiler could infer, so the call fails to compile. Use `slices.SortFunc` and supply a function that returns a negative, zero or positive `int` for the pair, which is where you decide which field the order is on.
  • Is slices.Sort stable, and why is there no slices.SortStable?
    It is not guaranteed stable. For ordered element types that is unobservable: two equal ints or equal strings are the same value, so their relative order carries no information. Stability only becomes visible when equal keys sit on distinguishable payloads, and that case necessarily needs a comparison function - which is why the package offers `slices.SortStableFunc` and no plain `SortStable`.

It is re-shelving the books on the shelf they already occupy. No second shelf appears, and the arrangement you walked in with is gone.

saying these in an interview costs you the question

  • Says slices.Sort returns a new sorted slice
  • Assigns the result: xs = slices.Sort(xs)
  • Thinks it can sort a slice of structs directly
  • Assumes equal elements keep their original relative order
  • Believes sorting a parameter leaves the caller's order intact