英文:
Print all values in map recursively in Go
问题
假设我有这样一张地图:
var results map[string]interface{}
值可以是任何类型,甚至是另一个地图。我该如何打印出所有的值?如果值是一个数组,我想要逐个打印数组中的每个项。如果它是另一个地图,我想要在地图上递归调用同一个函数。
英文:
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.
答案1
得分: 1
我无耻地从某个网站上抄袭了这段代码:
import (
"fmt"
"reflect"
"strings"
)
/*
InspectStruct打印实例化结构体的内部细节。非常适用于调试。
用法:InspectStruct(req, 0) -> 打印所有子元素
*/
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)
}
这段代码用于打印实例化结构体的内部细节,非常适用于调试。你可以使用InspectStruct(req, 0)
来打印所有子元素。
英文:
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\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)
}
答案2
得分: 0
使用fmt.Printf
中的%v
可以遍历内部的映射并打印元素,通过调用每个元素的String()
方法。现在,如果你想改变内部类型的默认打印方式,只需在该类型上实现String()
方法。在下面的示例中,我创建了一个每行打印一个整数的[]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
英文:
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\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)
}
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]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论