How to Find the Maximum or Minimum of a Slice in Go
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 to prefer max(a, b) over manual conditionals.
Using the Standard Library slices Package (Go 1.21+)
According to 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 and tested in 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) Tfunc slices.Min[T constraints.Ordered](s []T) T
These return the maximum and minimum elements respectively, panicking if the slice is empty.
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) Tfunc 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.
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, 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+.
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 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.
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.Maxandslices.Minfrom 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.MaxFuncandslices.MinFuncfor custom comparison logic without requiring types to implementsort.Interface. - Import
golang.org/x/exp/slicesfor 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →