Search code examples
gotypesinterfacetype-assertion

Golang - Sum of an [...]interface{}


I have created a generic data structure, with a name and a generic array in Golang.

package main

import "fmt"

type NamedArray struct {
  Name string
  values []interface{}
}

func main() {
  data := [...]int{1, 2, 3, 4, 5}
  interfaced_data := make([]interface{}, len(data))
  for i, v := range data{
    interfaced_data[i] = v
  }
  int_arr := NamedArray{Name: "Int Array", values: interfaced_data}
  fmt.Println(int_arr)
  // fmt.Println(int_arr.Sum()) -- uncomment to run Sum

  data_float := [...]float64{0.1, 0.2, 0.3, 0.4, 0.5}
  interfaced_data_float := make([]interface{}, len(data_float))
  for i, v := range data_float{
    interfaced_data_float[i] = v
  }
  float_arr := NamedArray{Name: "Float Array", values: interfaced_data_float}
  fmt.Println(float_arr)
  // fmt.Println(int_arr.Sum()) -- uncomment to run Sum
}

Now I want to define a method which allows me to sum all the values in the array. I know that they are numeric (though whether they are int or float is dependant on context) but I am having some serious trouble.

func (arr NamedArray) Sum() interface{} {
  data := arr.values
  sum := 0
  for i, v := range data {
    sum += v
  }
  return sum
}

I can't seem to make this work, though. When I uncomment lines 18 and 27 (fmt.Println(int_arr.Sum() and fmt.Println(int_arr.Sum()) and try to run the code I get

34:9: invalid operation: sum += v (mismatched types int and interface {})

During compilation.

Does anyone know how to add generic types, given we know that they are numeric?

Thanks!


Solution

  • The + operator is not defined on values of type interface{}. You have to get a value of type int out of the interface{} values before you can work with it as a number.

    For that, you may use type assertion. See this example:

    s := []interface{}{1, 2, 3, "invalid"}
    
    sum := 0
    for _, v := range s {
        if i, ok := v.(int); ok {
            sum += i
        } else {
            fmt.Println("Not int:", v)
        }
    }
    fmt.Println("Sum:", sum)
    

    Output (try it on the Go Playground):

    Not int: invalid
    Sum: 6
    

    The above example only handles int numbers, and nothing else. If you want to "support" multiple number types, a more convenient way would be to use a type switch:

    s := []interface{}{1, int32(2), int8(3), "invalid"}
    
    sum := 0
    for _, v := range s {
        switch i := v.(type) {
        case int:
            sum += i
        case int32:
            sum += int(i)
        case int8:
            sum += int(i)
        default:
            fmt.Println("Not int:", v)
        }
    }
    fmt.Println("Sum:", sum)
    

    Output is the same. Try this one on the Go Playground.