在Go中以递归方式打印地图中的所有值

时间:2015-02-27 22:32:23

标签: go

假设我有这种类型的地图:

var results map[string]interface{}

值可以是任何东西,甚至是另一张地图。我如何打印所有值?如果值是一个数组,我想单独打印数组中的每个项目。如果它是另一个地图,我想在地图上递归调用相同的函数。

2 个答案:

答案 0 :(得分:0)

我前一段时间从一个网站上无耻地撕掉了这个:

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\n",
            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)
}

答案 1 :(得分:0)

在fmt.Printf上使用%v将遍历内部地图并打印元素 也可以通过调用每个上的String()来实现。现在,如果要在内部类型上更改此默认打印,则只需在该类型上实现String()。在下面的例子中,我创建了一个[] int版本,每行打印一个int。

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\n", 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\n", foo)
    fmt.Printf("bar is :%v\n", bar)
}

打印:

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]

http://play.golang.org/p/kc6xm7dHwx