Как выполнить итерацию через интерфейс map [string] {} - PullRequest
0 голосов
/ 05 ноября 2018

Я столкнулся с проблемой рекурсивного перебора интерфейса map [string] {} с дополнительными условиями.

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
}

StackTrace:

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

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Используйте следующий код для просмотра карт, массивов и фрагментов любого типа:

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
    }
}
0 голосов
/ 05 ноября 2018

Следующее работает на меня

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...