I am writing a collector that collects metrics and stores in structs that looks something like this:
type Metric struct {
Name string
Data []float64
}
However for some metrics, it does not make sense to use float64, since their values are unsigned integers. Any idea how I could use different numeric types for the Data
field?
I could use Data []interface{}
, but then I won't be able to use indexing on the array elements.
(For clarity: I don't need different types in one slice, like a list in Python: my slice has to be strongly typed, but I want to be able to change the type of the slice.)
For a full solution to this, you'll have to wait until generics lands in Go (potentially in 1.18): https://blog.golang.org/generics-proposal
With generics, you'd be able to have a generic Metric
type that can either hold float64
or unsigned
, and you could instantiate each of them separately.
E.g. (generics-enabled playgorund):
type Metric[T any] struct {
Name string
Data []T
}
func main() {
mf := Metric[float64]{"foo", []float64{12.24, 1.1, 2.22}}
mu := Metric[uint32]{"bar", []uint32{42, 2}}
fmt.Println(mf)
fmt.Println(mu)
}
Note that [T any]
means that the type held in Data
is unconstrained. You can constrain it to types with certain characteristics, or to a hardcoded list like float64, uint32
if you prefer.
In the meanwhile, there are some options:
float64
can represent a lot of integers; at least all 32-bit ones (see Representing integers in doubles)Data []interface{}
, but it's rather wasteful. There should be no problem indexing into this slice, but you'll have to have type asserts whenever you work with it. It's costly both memory-wise and runtime performance-wise; something that can really matter for metrics.Metric
, with code duplication (and use code generation to help, if needed).