I have a map of arrays of maps map[string][]map[string]string
, only, when I get the data, it's in the format map[interface{}]map[interface{}][]map[interface{}]interface{}
, so I'm left to do a bunch of nested type assertions, which is really clunky, takes a long time to write, is hard to read/write, and is probably error prone, like this;
if key == "identities" {
idErrMessage := "Sorry, there was a problem with an identity"
idArray, ok := setting.(map[string]interface{})
if ok {
for idType, ids := range idArray {
idGroupArray, ok := ids.([]interface{})
if ok {
for _, idGroup := range idGroupArray {
id, ok := idGroup.(map[interface{}]interface{})
if ok {
log.Println("type:", idType)
for key, val := range id {
log.Printf("%v: %v", key, val)
}
} else {
log.Fatal(idErrMessage)
}
}
} else {
log.Fatal(idErrMessage)
}
}
} else {
log.Fatal(idErrMessage)
}
}
I've been searching for a few hours now, and I can't seem to find an easier way to do this than the code above.
Is there anyway I can just v, ok := setting.(map[string]map[string][]map[string]string)
, or am I just stuck with the code above?
This is the final code I used:
if key == "identities" {
idTypes := convertToStringMap(setting)
ghIds := convertToMapSlice(idTypes["github"])
for _, ghId := range ghIds {
for key, value := range convertToStringMap(ghId) {
log.Println(key, value)
}
}
}
it basically converts the interfaces to map[string]interface{} one step at a time, which is the best way to do it I've found, and at least you stay out of nesting hell.
These are the function to convert to the proper types:
func convertToStringMap(i interface{}) map[string]interface{} {
v, ok := i.(map[string]interface{})
if !ok {
v, ok := i.(map[interface{}]interface{})
if ok {
m2 := map[string]interface{}{}
for k, v := range v {
m2[k.(string)] = v
}
return m2
} else {
log.Fatal("There was a problem converting to a string map")
}
}
return v
}
func convertToMapSlice(i interface{}) []interface{} {
v, ok := i.([]interface{})
if !ok {
log.Fatal("There was a problem converting to a slice")
}
return v
}
Overall though, I think I'm just going to find a work around so I don't have to do this at all.
You can define a struct with the expected structure, and try to unmarshal to it with something like this:
https://github.com/mitchellh/mapstructure
I never tried it with map[interface{}]interface{} though.