Jared Mackey
Jared Mackey

Reputation: 4158

Dynamically add values together

I am trying to create a service that looks at structs meta data and will figure out which fields to add together. Here is a sample Struct and the function I have been using in Go Playground to add things together. This is a just a sample struct, obviously not all fields would be increment.

It is panic with "panic: interface conversion: interface is int, not int64", how do I do this the right way?

package main

import (
   "fmt"
   "reflect"
   "strconv"
)

type TestResult struct {
    Complete         int        `json:"complete" increment:"true"`
    Duration         int        `json:"duration" increment:"true"`
    Failed           int        `json:"failed" increment:"true"`
    Mistakes         int        `json:"mistakes" increment:"true"`
    Points           int        `json:"points" increment:"true"`
    Questions        int        `json:"questions" increment:"true"`
    Removal_duration int        `json:"removal_duration" increment:"true"`
}

func main() {
    old := TestResult{}
    new := TestResult{}

    old.Complete = 5
    new.Complete = 10

    values := reflect.ValueOf(old)
    new_values := reflect.ValueOf(new)
    value_type := reflect.TypeOf(old)
    fmt.Println(values)
    fmt.Println(new_values)

    for i := 0; i < values.NumField(); i++ {
       field := value_type.Field(i)
       if increment, err := strconv.ParseBool(field.Tag.Get("increment")); err == nil && increment {
          reflect.ValueOf(&new).Elem().Field(i).SetInt(new_values.Field(i).Interface().(int64) + values.Field(i).Interface().(int64))
       }
    }
    fmt.Println(new)
}

Playground: https://play.golang.org/p/QghY01QY13

Upvotes: 1

Views: 303

Answers (1)

Thundercat
Thundercat

Reputation: 121119

Because the fields are of type int, you must type assert to int.

reflect.ValueOf(&new).Elem().Field(i).SetInt(int64(new_values.Field(i).Interface().(int) + values.Field(i).Interface().(int)))

playground example

Another approach is to use the Int() instead of Interface().(int). This approach works with all signed integer types:

reflect.ValueOf(&new).Elem().Field(i).SetInt(new_values.Field(i).Int() + values.Field(i).Int())

playground example

Here's how to do it for all numeric types:

        v := reflect.ValueOf(&new).Elem().Field(i)
        switch v.Kind() {
        case reflect.Int,
            reflect.Int8,
            reflect.Int16,
            reflect.Int32,
            reflect.Int64:
            v.SetInt(new_values.Field(i).Int() + values.Field(i).Int())
        case reflect.Uint,
            reflect.Uint8,
            reflect.Uint16,
            reflect.Uint32,
            reflect.Uint64:
            v.SetUint(new_values.Field(i).Uint() + values.Field(i).Uint())
        case reflect.Float32, reflect.Float64:
            v.SetFloat(new_values.Field(i).Float() + values.Field(i).Float())
        }

playground example

Upvotes: 2

Related Questions