# How to Find the Maximum or Minimum of a Slice in Go

> Discover modern Go techniques to find the maximum or minimum of a slice using standard library functions like slices Max and Min. Learn custom comparison with MaxFunc and MinFunc.

- Repository: [JetBrains/go-modern-guidelines](https://github.com/jetbrains/go-modern-guidelines)
- Tags: how-to-guide
- Published: 2026-08-29

---

**Use the generic `slices.Max` and `slices.Min` functions from the standard library's `slices` package (Go 1.21+) to locate extrema with compile-time type safety, or use `slices.MaxFunc` and `slices.MinFunc` for custom comparison logic.**

The JetBrains/go-modern-guidelines repository establishes that modern Go code should leverage standard library generics rather than manual loops when you need to find the maximum or minimum of a slice in Go. Starting with Go 1.21, the `slices` package provides optimized, generic helpers that eliminate boilerplate while maintaining performance comparable to hand-written iterations, aligning with the guideline documented in [`README.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/README.md) to prefer `max(a, b)` over manual conditionals.

## Using the Standard Library slices Package (Go 1.21+)

According to [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go), the canonical approach for Go 1.21 and later utilizes the `slices` package introduced in the standard library. These functions are defined in [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go) and tested in [`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go), replacing older ad-hoc implementations.

### Basic Usage with slices.Max and slices.Min

For types that satisfy `constraints.Ordered` (integers, floats, strings), use the type-parameterized functions:

- `func slices.Max[T constraints.Ordered](s []T) T`
- `func slices.Min[T constraints.Ordered](s []T) T`

These return the maximum and minimum elements respectively, panicking if the slice is empty.

```go
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{3, 7, 2, 9, 5}
    maxVal := slices.Max(nums) // returns 9
    minVal := slices.Min(nums) // returns 2
    fmt.Println("max:", maxVal, "min:", minVal)
}

```

### Custom Comparisons with slices.MaxFunc and slices.MinFunc

For complex types or non-standard ordering, use the comparison function variants that accept a custom comparator:

- `func slices.MaxFunc[T any](s []T, cmp func(a, b T) int) T`
- `func slices.MinFunc[T any](s []T, cmp func(a, b T) int) T`

The comparison function should return a negative integer if `a < b`, zero if `a == b`, and positive if `a > b`.

```go
package main

import (
    "fmt"
    "slices"
)

func main() {
    strs := []string{"go", "golang", "gopher"}
    
    // Find string with maximum length
    longest := slices.MaxFunc(strs, func(a, b string) int {
        return len(a) - len(b)
    })
    fmt.Println("longest:", longest) // outputs: "golang"
}

```

## Backwards Compatibility with golang.org/x/exp/slices

For projects constrained to Go versions earlier than 1.21, the experimental package provides identical APIs. As noted in [`plugin/skills/use-modern-go/SKILL.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/plugin/skills/use-modern-go/SKILL.md), this serves as a forward-compatible bridge until the project upgrades its `go.mod` directive. The package adds zero runtime cost and ensures seamless migration to the standard library once you target Go 1.21+.

```go
package main

import (
    "fmt"
    "golang.org/x/exp/slices"
)

func main() {
    floats := []float64{2.5, 7.3, 1.4, 9.0}
    fmt.Println("max:", slices.Max(floats)) // 9.0
    fmt.Println("min:", slices.Min(floats)) // 1.4
}

```

## Manual Iteration for Legacy Environments

While the guidelines in [`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go) explicitly discourage manual loops in favor of generic utilities, a fallback implementation remains valid for environments without generic support. However, this violates the repository's principle of using modern idioms.

```go
func MaxIntSlice(s []int) int {
    if len(s) == 0 {
        panic("empty slice")
    }
    max := s[0]
    for _, v := range s[1:] {
        if v > max {
            max = v
        }
    }
    return max
}

```

## Summary

- **Use `slices.Max` and `slices.Min`** from the standard library for ordered types in Go 1.21+ as the primary method to find the maximum or minimum of a slice in Go.
- **Apply `slices.MaxFunc` and `slices.MinFunc`** for custom comparison logic without requiring types to implement `sort.Interface`.
- **Import `golang.org/x/exp/slices`** for projects supporting Go 1.20 or earlier, maintaining API compatibility for future migration to the standard library.
- **Avoid manual for-loops** unless operating in legacy environments without generic support, per the guidelines established in the JetBrains repository.

## Frequently Asked Questions

### What is the most efficient way to find the maximum of a slice in Go?

The most efficient modern approach uses `slices.Max` from the standard library's `slices` package (Go 1.21+). According to the source analysis, these functions compile to optimized implementations comparable to hand-written loops while providing compile-time type safety through generics. For custom types, `slices.MaxFunc` offers equivalent performance without the allocation overhead of interface boxing.

### How do I handle empty slices when calling slices.Max?

Both `slices.Max` and `slices.Min` will panic if called with an empty slice, as the functions return the underlying type `T` rather than a tuple or error. You must validate slice length (`len(s) > 0`) before calling these functions. This behavior is consistent across both the standard library and `golang.org/x/exp/slices` implementations referenced in the JetBrains guidelines.

### Can I use slices.Min with custom types?

You cannot use `slices.Min` directly with custom types unless they satisfy `constraints.Ordered` (supporting `<`, `>`, `==` operators). For structs or other complex types, use `slices.MinFunc`, which accepts a comparison function `func(a, b T) int` returning a negative value when `a < b`, zero when equal, and positive when `a > b`. This pattern, documented in the repository's guidelines, provides flexibility without requiring type modification.

### When should I use the experimental slices package instead of the standard library?

Use `golang.org/x/exp/slices` only when your project's `go.mod` specifies a Go version older than 1.21. The experimental package provides identical function signatures to the standard library, ensuring zero-friction migration when upgrading Go versions. Once targeting Go 1.21 or later, migrate import paths from `golang.org/x/exp/slices` to `slices` to eliminate external dependencies, as recommended in [`plugin/skills/use-modern-go/SKILL.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/plugin/skills/use-modern-go/SKILL.md).