【问题标题】:How to iterate recursively through map[string]interface{}如何通过 map[string]interface{} 递归迭代
【发布时间】:2018-11-05 10:46:42
【问题描述】:

我遇到了一个问题,如何使用附加条件递归地遍历 map[string]interface{}。

1) 如果一个值是一个映射 - 递归调用该方法

2) 如果一个值是一个数组 - 数组的调用方法

3) 如果值不是映射 - 处理它。

现在当方法尝试执行doc.throughMap(mv) - 发生错误 那么在reflect 确认值是映射还是数组之后,如何将某些值转换为所需的类型?

type MapType map[string]interface{}
type ArrayType []interface{}
func (doc *Document) throughMap(docMap MapType) MapType {
    for k, v := range docMap {
        vt := reflect.TypeOf(v)
        switch vt.Kind() {
        case reflect.Map:
            if mv, ok := v.(map[string]interface{}); ok {
                docMap[k] = doc.throughMap(mv)
            } else {
                panic("error.")
            }
        case reflect.Array, reflect.Slice:
            if mv, ok := v.([]interface{}); ok {
                docMap[k] = doc.throughArray(mv)
            } else {
                panic("error.")
            }
        default:
            docMap[k] = doc.processType(v)
        }
    }
    return docMap
}

堆栈跟踪:

panic: error. [recovered]
    panic: error.

goroutine 1 [running]:
encoding/json.(*encodeState).marshal.func1(0xc000074cd0)
    /usr/local/go/src/encoding/json/encode.go:301 +0x9a
panic(0x4bd700, 0x4f9b70)
    /usr/local/go/src/runtime/panic.go:513 +0x1b9
project-name/package/name.(*Document).throughMap(0xc00000c028, 0xc000060180, 0xc00007e000)
    /home/path/to/project/document.go:231 +0x3f4
project-name/package/name.(*Document).convertDocument(0xc00000c028)
    /home/path/to/project/document.go:217 +0x33
project-name/pachage/name.(*Document).MarshalJSON(0xc00000c028, 0x4db740, 0xc00000c028, 0x7f3f0f7540c0, 0xc00000c028, 0xc00001c101)
    /home/path/to/project/document.go:167 +0xd8
encoding/json.marshalerEncoder(0xc00007c000, 0x4db740, 0xc00000c028, 0x16, 0xc000070100)
    /usr/local/go/src/encoding/json/encode.go:453 +0xb7
encoding/json.(*encodeState).reflectValue(0xc00007c000, 0x4db740, 0xc00000c028, 0x16, 0x4c0100)
    /usr/local/go/src/encoding/json/encode.go:333 +0x82
encoding/json.(*encodeState).marshal(0xc00007c000, 0x4db740, 0xc00000c028, 0x4f0100, 0x0, 0x0)
    /usr/local/go/src/encoding/json/encode.go:305 +0xf4
encoding/json.Marshal(0x4db740, 0xc00000c028, 0xc000034698, 0x3, 0x3, 0x4d, 0x0)
    /usr/local/go/src/encoding/json/encode.go:160 +0x52
main.main()
    /home/path/to/project/main.go:21 +0x34d

【问题讨论】:

  • “我遇到了一个问题……” 那是什么问题?
  • 抱歉,已添加。
  • " 发生错误" 什么样的错误?请更具体。
  • 同样,如果地图内的所有地图都是具体类型map[string]interface{},您可以使用简单的类型转换或切换。如果内部地图地图是其他自定义地图类型,该地图作为底层类型,您可以使用reflect.Value.Conver()统一处理它们。
  • 如果切片和映射始终是具体类型[]interface{}map[string]interface{},则使用类型断言遍历结构。例如,请参阅答案here。如果不是,则对所有操作使用反射。请参阅答案here 作为起点(可能有一个更好的使用反射的示例,但我无法快速找到它)。

标签: go recursion


【解决方案1】:

使用以下代码递归遍历任何类型的映射、数组和切片:

func walk(v reflect.Value) {
    fmt.Printf("Visiting %v\n", v)
    // Indirect through pointers and interfaces
    for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
        v = v.Elem()
    }
    switch v.Kind() {
    case reflect.Array, reflect.Slice:
        for i := 0; i < v.Len(); i++ {
            walk(v.Index(i))
        }
    case reflect.Map:
        for _, k := range v.MapKeys() {
            walk(v.MapIndex(k))
        }
    default:
        // handle other types
    }
}

【讨论】:

    【解决方案2】:

    以下对我有用

    func main() {
        x := MapType{
            "a": MapType{
                "x": MapType{
                    "p": ArrayType{"l", "o", "l"},
                },
            } ,
        }
        d := &Document{}
        fmt.Println(d.throughMap(x))
    
    }
    
    type Document struct {}
    
    type MapType map[string]interface{}
    type ArrayType []interface{}
    func (doc *Document) throughMap(docMap MapType) MapType {
        for k, v := range docMap {
            fmt.Println(k, v)
            vt := reflect.TypeOf(v)
            switch vt.Kind() {
            case reflect.Map:
                if mv, ok := v.(MapType); ok {
                    docMap[k] = doc.throughMap(mv)
                } else {
                    panic("error.")
                }
            case reflect.Array, reflect.Slice:
                if mv, ok := v.(ArrayType); ok {
                    docMap[k] = doc.throughArray(mv)
                } else {
                    panic("error.")
                }
            default:
                docMap[k] = doc.processType(v)
            }
        }
        return docMap
    }
    
    func (doc *Document) throughArray(arrayType ArrayType) ArrayType  {
        return arrayType
    }
    
    func (doc *Document) processType(x interface{}) interface{} {
        return x
    }
    

    【讨论】:

    • 一个案例中的问题,外部地图包含另一个不同类型的地图。嵌套 := map[string]int{ "rsc": 5, "gri": 52, } 提交 := map[string]interface{}{ "rsc": 3711, "adg": 嵌套, }
    猜你喜欢
    • 2018-01-06
    • 2023-03-15
    • 1970-01-01
    • 2015-01-14
    • 2013-12-18
    • 1970-01-01
    • 2021-06-11
    • 2021-05-26
    • 1970-01-01
    相关资源
    最近更新 更多