The Go programming language is constantly evolving, regularly introducing new exciting features that boost development efficiency and improve code maintainability. The latest release Go 1.21 brings many exciting things, from profile-guided optimization to standard library packages for structured logging, slices and maps operations (see the full release notes for more details). But in this post I want to describe two new built functions that caught my eye: min and max.
These functions are designed to provide concise and straightforward ways to compute the smallest and largest values from ordered types. Both functions accept values of an ordered type: integers, floats, or strings (or their derived types) and at least one argument should be specified.
minValue := min(4, 8, 1) // min, integers fmt.Println(minValue) // 1 maxValue := max(4, 8, 1) // max, integers fmt.Println(maxValue) //8 minFloat := min(1.23, 0.99, 16.78) // min, floats fmt.Println(minFloat) // 0.99 minX := min(1.23, 2, 99, 0.5) // integers and floats fmt.Println(minX) // 0.5, float maxString := max("b", "abc", "x", "pq", "qp") // max, strings fmt.Println(maxString) // "x" type MyInt int a := MyInt(6) b := MyInt(78) c := max(a, b) fmt.Println(c) // 78
For floating-point arguments negative zero, NaN, and infinity the following rules apply:
x | y | min(x, y) | max(x, y) | Notes |
---|---|---|---|---|
-0.0 | 0.0 | -0.0 | 0.0 | negative zero is smaller than (non-negative) zero |
-Inf | y | -Inf | y | negative infinity is smaller than any other number |
+Inf | y | y | +Inf | positive infinity is larger than any other number |
NaN | y | NaN | NaN | if any argument is a NaN, the result is a NaN |
Please, keep in mind, that these functions do not work with slices. To work with slices, use slices package instead as shown below:
input := []int{1, 2, 3} // Do not work with slices. The following won't compile. // m := min(input) // invalid argument: input (variable of type []int) cannot be ordered // To work with slices, use slices package. m := slices.Min(input) fmt.Println(m) // 1
Also, I would like to mention that these functions won’t break the existing code that already uses the names min and max. Builtins aren’t keywords and you can shadow them:
max := "This is Max" min := 8 - 3 fmt.Println(max, min) // This is Max 5