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…]