How to Find the Minimum or Maximum of Values in Modern Go

Use slices.Min and slices.Max from the Go 1.21+ standard library to extract the smallest or largest element from ordered slices without writing manual comparison loops.

The JetBrains/go-modern-guidelines repository establishes that the modern Go way to find the minimum or maximum of values relies on standard library helpers rather than traditional iteration. These functions eliminate boilerplate code, reduce error-prone comparison logic, and clearly signal intent when working with ordered types.

Why Use slices.Min and slices.Max

According to the JetBrains/go-modern-guidelines source code, you should use slices.Max and slices.Min instead of manual loops over ordered values. This guideline appears in FEATURES.md at lines 1264–1266 and is encoded in the machine-readable internal/guidelines/guidelines.json at lines 935–948.

The slices package provides these functions specifically for ordered constraints—any type that supports <, <=, >, or >= operators. This includes:

  • Integer types (int, int64, uint, etc.)
  • Floating-point types (float32, float64)
  • Strings (compared lexicographically)

Introduced in Go 1.21 and fully supported for Go 1.25+ in the guidelines, these functions transform verbose loop-and-compare patterns into single, readable function calls.

Working with Ordered Types

The slices.Min and slices.Max functions accept a slice of any ordered type and return the corresponding extreme value. The type constraint constraints.Ordered (from the golang.org/x/exp/constraints package in earlier versions, now integrated into the standard library) ensures compile-time safety.

When you pass a slice to these functions, they perform an optimized linear scan internally—equivalent to the manual loop you would write, but without the risk of off-by-one errors or incorrect initial value assignments.

Practical Code Examples

Here is how to apply the modern approach across different ordered types:

package main

import (
	"fmt"
	"slices"
)

func main() {
	// Integer slice – find max & min
	ints := []int{42, 7, 19, 33}
	maxInt := slices.Max(ints) // 42
	minInt := slices.Min(ints) // 7
	fmt.Printf("int  max=%d  min=%d\n", maxInt, minInt)

	// Float slice – works with any ordered type
	floats := []float64{3.14, 2.71, 1.62}
	fmt.Printf("float max=%g  min=%g\n", slices.Max(floats), slices.Min(floats))

	// String slice – lexicographic ordering
	names := []string{"alice", "bob", "charlie"}
	fmt.Printf("lexicographic max=%s  min=%s\n", slices.Max(names), slices.Min(names))
}

The go.mod file in the JetBrains/go-modern-guidelines repository specifies a minimum Go version of 1.25, ensuring the slices package is available without external dependencies.

Critical Safety Considerations

Never call these functions on empty slices. Both slices.Min and slices.Max panic if the provided slice has length zero. You must explicitly guard against emptiness:

if len(values) == 0 {
    // Handle empty case appropriately
    return 0, errors.New("empty slice")
}
return slices.Max(values), nil

When to Stick with Manual Loops

While the modern standard library approach covers most scenarios, explicit iteration remains necessary in two specific cases:

  1. Empty slice handling: When you need to return a zero value or error instead of panicking.
  2. Custom comparisons: When working with structs or complex types requiring non-standard ordering (e.g., comparing User structs by age field).

For custom ordering, either maintain an explicit loop or use sort.Slice to sort the collection first, then access the first or last element.

Summary

  • Use slices.Min and slices.Max for cleaner, idiomatic code when finding extremes in ordered slices.
  • Verify slice length before calling these functions to avoid runtime panics.
  • Prefer manual loops or sorting only when handling empty collections or implementing custom comparison logic.
  • Reference FEATURES.md and guidelines.json in the JetBrains/go-modern-guidelines repository for the canonical implementation rules.

Frequently Asked Questions

What happens if I call slices.Min or slices.Max on an empty slice?

Both functions panic at runtime. The implementations require at least one element to establish a baseline for comparison. Always check len(slice) > 0 before invocation, or use a manual loop that returns a default value for empty inputs.

Can I use slices.Min and slices.Max with custom structs?

No. These functions only accept types satisfying the Ordered constraint (numbers and strings). For structs or types requiring custom comparison logic, implement an explicit loop or define a Less method and use sort.Slice or slices.SortFunc followed by index access.

What Go version do I need to use these functions?

You need Go 1.21 or later, where the slices package entered the standard library. The JetBrains/go-modern-guidelines repository specifically targets Go 1.25+ in its go.mod file, ensuring full compatibility with the latest slice manipulation utilities.

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 →