To calculate the arithmetic mean (average value) in Go, you should write your own function that takes a slice of numbers as an input, sum all values in the slice, and divides the sum by the number of elements.
package main
import "fmt"
func mean(data []float64) float64 {
if len(data) == 0 {
return 0
}
var sum float64
for _, d := range data {
sum += d
}
return sum / float64(len(data))
}
func main() {
fmt.Println(mean([]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))
}
This function requires that the input slice to be of a certain type, such as float64
. In case you want to calculate the mean for a slice of, for example, int
values, until recently you had to write a separate function that differed only in that it accepted an int
slice as an argument. Another solution was to convert the slice to float64
before the calculation. However, the new version of Go 1.18, which introduced Generics, allows you to simplify this problem. All you need to do is write a generic mean()
function that takes a slice of any numeric type.
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
type Number interface {
constraints.Float | constraints.Integer
}
func mean[T Number](data []T) float64 {
if len(data) == 0 {
return 0
}
var sum float64
for _, d := range data {
sum += float64(d)
}
return sum / float64(len(data))
}
func main() {
fmt.Println(mean([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))
fmt.Println(mean([]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))
}
If you are not already familiar with the basics of Generics in Go, check out our series of articles: Introduction to Go Generics by example.
Check also our example on how to calculate median in Go.
In the example above, we start with the custom constraint declaration. The Number
interface is a type set being union of constraints.Float
and constraints.Integer
.
This is a new feature released along with Generics in Go 1.18 - now interfaces can have not only a set of methods but also a set of types. Just use the |
operator to declare the set of types that our generic function should accept. In our case, we accept constraints.Float
and constraints.Integer
types, which are themselves type sets containing all floating and integer point types.
The rest of the new mean()
function is the same as in the non-generic version. The only difference is that we use type T
instead of float64
for the input data. The function result is still float64
, because no matter if the input is a slice of integers or floating-point numbers, we can get a floating-point number as the result of the mean.