Suppose I have a map of this type:
var results map[string]interface{}
The values can be anything, even another map. How would I print all the values? If the value is an array, I want to print each item in the array individually. If it is another map, I want to recursively call the same function on the map.
I shamelessly ripped this from a site some time ago:
import (
"fmt"
"reflect"
"strings"
)
/*
InspectStruct prints the guts of an instantiated struct. Very handy for debugging
usage: InspectStruct(req, 0) -> prints all children
*/
func InspectStructV(val reflect.Value, level int) {
if val.Kind() == reflect.Interface && !val.IsNil() {
elm := val.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
val = elm
}
}
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
address := "not-addressable"
if valueField.Kind() == reflect.Interface && !valueField.IsNil() {
elm := valueField.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
valueField = elm
}
}
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
address = fmt.Sprintf("0x%X", valueField.Addr().Pointer())
}
fmt.Printf("%vField Name: %s,\t Field Value: %v,\t Address: %v\t, Field type: %v\t, Field kind: %v
",
strings.Repeat("\t", level),
typeField.Name,
//valueField.Interface(),
address,
typeField.Type,
valueField.Kind())
if valueField.Kind() == reflect.Struct {
InspectStructV(valueField, level+1)
}
}
}
func InspectStruct(v interface{}, level int) {
InspectStructV(reflect.ValueOf(v), level)
}
Using %v on fmt.Printf will traverse the inner maps and print the elements too by calling String() on each. Now if you want to change this default printing on an inner type you just have to implement String() on that type. in the following example i created a version of []int that prints one int per line.
package main
import (
"fmt"
"strings"
)
type OnePerLineInt []int
func (ip OnePerLineInt) String() string {
var ret []string
for _, a := range ip {
ret = append(ret, fmt.Sprintf("Item: %v
", a))
}
return strings.Join(ret, "")
}
func main() {
arr := &OnePerLineInt{1, 2, 3}
arr1 := []int{4, 5 , 6}
foo := make(map[string]interface{})
bar := make(map[string]interface{})
bar["a"] = "foobar1"
bar["b"] = "foobar2"
foo["1"] = arr
foo["2"] = bar
foo["3"] = arr1
fmt.Printf("foo contents: %v
", foo)
fmt.Printf("bar is :%v
", bar)
}
prints:
foo contents: map[1:Item: 1
Item: 2
Item: 3
2:map[a:foobar1 b:foobar2] 3:[4 5 6]]
bar is :map[a:foobar1 b:foobar2]