Attempting to iterate over a map[string]interface{} type in GoLang to retrieve the field key’ed as ‘status’. Known: the interface{} type for the value is _either_ a string OR another map[string]interface{}…
Unsuccessful attempt:
func (paramToCheck string) findKey(keyToCheck string) (string, bool) {
return keyToCheck, (keyToCheck == paramToCheck)
}
func (paramToCheck map[string]interface{}) findKey(key string) (string, bool) {
for key, value := range paramToCheck {
foundValue, found := value.findKey(key)
if found {
return foundValue, true
}
}
return key, false
}
func (val interface{}) findKey(key string) (string, bool) {
fmt.Println("Unable to find value...")
return key, false
}
Results of go install:
./parseResult.go:55: invalid receiver type map[string]interface {} (map[string]interface {} is an unnamed type)
./parseResult.go:57: value.findKey undefined (type interface {} is interface with no methods)
./parseResult.go:65: findKey redeclared in this block
previous declaration at ./parseResult.go:55
./parseResult.go:65: invalid receiver type interface {} (interface {} is an unnamed type)
./parseResult.go:78: value.findKey undefined (type interface {} is interface with no methods)
Back to the drawing board… The other day, I also tried a switch statement approach like the below…
switch val := v.(type) {
case string:
fmt.Println(val)
checkVal = val
case map[string]interface{}:
fmt.Println("Found interface...")
for k, v := range val {
switch val := v.(type) {
case string:
fmt.Println(val)
checkPhase(k, checkVal)
case map[string]interface{}:
fmt.Println("Found ANOTHER interface map...")
}
}
}
I ended up realizing I needed something a bit more recursive, since I know there are at least 3 levels of map[string]interface{} gook in my data set.
Looking at what I’ve got, suspect what I need to is blend the function approach with the switch statement approach and duck the attempt to add polymorphic methods to string.. Huh. Why didn’t I see that before starting this blog post?? Good blog audience who hasn’t even seen this. Just attempting to describe this to you may have got me a solution. Saving my draft here and trying it out…
OK… results that did what I want… Bingo!!!
func findKey(key string, value interface{}, checkKey string) (string, bool) {
fmt.Printf("findKey for %v against checkKey %v\n", key, checkKey)
switch val := value.(type) {
case string:
return val, (key == checkKey)
case map[string]interface{}:
for newKey, newValue := range val {
foundValue, found := findKey(newKey, newValue, checkKey)
if found {
return foundValue, found
}
}
}
return "", false
}
func ParseJobState(params map[string]interface{}) []JobOutcome {
// Example: non-compiling code: [1]JobOutcome != []JobOutcome.
// Size of array is included in its type. Use slices instead
//outcomesArray := [...]JobOutcome{firstOutcome}
//return outcomesArray
for key, value := range params {
statusValue, found := findKey(key, value, "status")
if found {
fmt.Printf("Status found: %v\n", statusValue)
break
}
}
}
[BLOGGER NOTE: Just added the Preserve Code Formatting plugin to WordPress – code blocks like the above work MUCH more nicely now… Thanks to http://blog.templatemonster.com/2011/04/15/wordpress-plugins-code-snippets-displaying/ for helping find a solution…]