Search code examples
gopolymorphismslicego-interface

Go: use slice of different numeric types as field of a struct


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.)


Solution

  • 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:

    1. float64 can represent a lot of integers; at least all 32-bit ones (see Representing integers in doubles)
    2. 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.
    3. You can have two versions of Metric, with code duplication (and use code generation to help, if needed).