1

I am trying to flatten a dynamic value in Go into a slice of key value pairs. So I define a struct as :

type KeyValuePair struct {
   key string
   value interface{}
}

For simple values like x = 10, the function should return []KeyValuePair{"x", 10}, for y = "hello", it should return []KeyValuePair{"y", "hello"}. For structs like x = {A: 10, B: "test"}, it should return []KeyValuePair{{"A", 10}, {"B", "test"}}. And it should handle nested structs like x = {A: 10, B: {C: true}} I tried the following using recursion but it's far from what I want even for built-in types like int.

func flattenObject(o interface{}) []KeyValuePair {
    var result []KeyValuePair
    t := reflect.TypeOf(o)
    switch t.Kind() {
    case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int32, reflect.Int64, reflect.String:
        //v := reflect.ValueOf(t)
        result = append(result, KeyValuePair{key: fmt.Sprintf("%s", o), value: o})
    case reflect.Struct:
        v := reflect.ValueOf(t)
        for i := 0; i < v.NumField(); i++ {
            kv := KeyValuePair{key: t.Field(i).Name, value: v.Field(i)}
            result = append(result, flattenObject(kv)...)
        }
    case reflect.Slice:
        v := reflect.ValueOf(t)
        if !v.IsNil() {
            for i := 0; i < v.Len(); i++ {
                result = append(result, flattenObject(v.Index(i))...)
            }
        }
    }
    return result
}
dragonfly02
  • 3,403
  • 32
  • 55
  • 2
    I'm afraid one part of your premises is wrong: functions in Go always receive values, not variables, so if you have `x = 10; fn(x)`, that `fn` has no way to know the value it received was extracted from a variable named "x". Moreover, if you have `func foo() { return 10 }; fn(foo())`, there is no named variable in the picture at all: `fn` directly receives what a call to `foo()` has returned. You could possibly have the name of the type of the incoming value as the key in the produced data structure, though. Not sure if this fits your needs. – kostix Oct 22 '22 at 10:01
  • Ah ok, that makes total sense. Yes I could pass in the name of the field into the function actually. @kostix. Thanks for the comment! – dragonfly02 Oct 22 '22 at 10:55
  • By the way, how the function is supposed to handle nested structs? That is, what `x = {A: 10, B: {C: true}}` is supposed to produce? – kostix Oct 22 '22 at 15:59
  • @kostix it should return `[]KeyValuePair{{"A", 10}, {"C", true}}` – dragonfly02 Oct 22 '22 at 23:29

0 Answers0