I am working with an api and I need to pass it a slice of structs. I have a slice of maps so I need to convert it to a slice of structs.
package main
import "fmt"
func main() {
a := []map[string]interface{}{}
b := make(map[string]interface{})
c := make(map[string]interface{})
b["Prop1"] = "Foo"
b["Prop2"] = "Bar"
a = append(a, b)
c["Prop3"] = "Baz"
c["Prop4"] = "Foobar"
a = append(a, c)
fmt.Println(a)
}
[map[Prop1:Foo Prop2:Bar] map[Prop3:Baz Prop4:Foobar]]
so in this example, I have the slice of maps a
, which contains b
and c
which are maps of strings with different keys.
I'm looking to convert a
to a slice of structs where the first element is a struct with Prop1
and Prop2
as properties, and where the second element is a struct with Prop3
and Prop4
as properties.
Is this possible?
I've looked at https://github.com/mitchellh/mapstructure but I wasn't able to get it working for my use case. I've looked at this answer: https://stackoverflow.com/a/26746461/3390419
which explains how to use the library:
mapstructure.Decode(myData, &result)
however this seems to assume that the struct of which result
is an instance is predefined, whereas in my case the structure is dynamic.
CodePudding user response:
What you can do is to first loop over each map individually, using the key-value pairs of each map you construct a corresponding slice of reflect.StructField
values. Once you have such a slice ready you can pass it to reflect.StructOf
, that will return a reflect.Type
value that represents the dynamic struct type, you can then pass that to reflect.New
to create a reflect.Value
which will represent an instance of the dynamic struct (actually pointer to the struct).
E.g.
var result []any
for _, m := range a {
fields := make([]reflect.StructField, 0, len(m))
for k, v := range m {
f := reflect.StructField{
Name: k,
Type: reflect.TypeOf(v), // allow for other types, not just strings
}
fields = append(fields, f)
}
st := reflect.StructOf(fields) // new struct type
sv := reflect.New(st) // new struct value
for k, v := range m {
sv.Elem(). // dereference struct pointer
FieldByName(k). // get the relevant field
Set(reflect.ValueOf(v)) // set the value of the field
}
result = append(result, sv.Interface())
}