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)
- You can use
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.
- You can have two versions of
Metric
, with code duplication (and use code generation to help, if needed).