Go语言 如何进行嵌套迭代

5ssjco0h  于 2023-05-04  发布在  Go
关注(0)|答案(1)|浏览(110)

我正在尝试为另一个软件开发一个扩展,它可以向Go中的应用程序发送请求。在Go程序(我现在称之为“程序”)中,一个目的是将JSON文件转换为可以迭代的格式。下面是我正在使用的JSON格式示例:

{
  "name": "Game-Name",
  "tree": {
    "$className": "DataModel",

    "ReplicatedStorage": {
      "$path": "src/ReplicatedStorage"
    },

    "ServerScriptService": {
      "$path": "src/ServerScriptService"
    },

    "ReplicatedFirst": {
      "$path": "src/ReplicatedFirst"
    },

    "ServerStorage": {
      "$path": "src/ServerStorage"
    }
  }
}

其理念是:

  • 迭代就可以接“名”了
  • 迭代可以拾取“$className”
  • 对于所有以“$path”作为索引的示例,在父src文件夹下创建一个文件夹,该文件夹具有父Map的索引。例如,ReplicatedStorage是路径为src/ReplicatedStorage的文件夹的名称

下面是用于执行此操作的流程函数:

func process(in interface{}) {
v := reflect.ValueOf(in)

    if v.Kind() == reflect.Map {
        for _, key := range v.MapKeys() {
            strct := v.MapIndex(key)
    
            index := key.Interface()
            value := reflect.ValueOf(strct.Interface())
    
            if index == "tree" {
                for _, treeKey := range value.MapKeys() {
                    treeIndex := treeKey.Interface()
    
                    fmt.Println("KEY")
                    fmt.Println(treeIndex)
    
                    if treeIndex != "$className" {
                        fmt.Println("bug")
                        fmt.Println(treeKey)
    
                        a := key.MapIndex(value) // panic serving ...: reflect: call of reflect.Value.MapIndex on string Value
                        b := reflect.ValueOf(a.Interface())
    
                        for _, key2 := range b.MapKeys() {
                            index2 := key2.Interface()
                            value2 := reflect.ValueOf(key2.Interface())
    
                            fmt.Println(index2)
                            fmt.Println(value2)
                        }
                    }
                }
            }
        }
    }

}

注解是错误的位置和内容。我还希望做的一件理想的事情是不必堆叠for循环,因为那是相当臭的代码。

waxmsbnn

waxmsbnn1#

通常的方法是解组到与数据结构匹配的Go类型。这里的问题是,树不能很容易地表示为Go类型(它有字符串类型的字段$classname,但在其他方面就像一个对象值包含$path字段的Map)。
让我们继续进行到interface{}的解封。
使用类型Assert而不是reflect包。使用Map索引来查找值,而不是循环遍历键并查找匹配项。

func process(in interface{}) error {
    top, ok := in.(map[string]interface{})
    if !ok {
        return errors.New("expected object at top level")
    }
    tree, ok := top["tree"].(map[string]interface{})
    if !ok {
        return errors.New(".tree not found")
    }
    name, ok := top["name"]
    if !ok {
        return errors.New(".name not found")
    }
    className, ok := tree["$className"].(string)
    if !ok {
        return errors.New(".tree.$className not found")
    }
    for k, v := range tree {
        thing, ok := v.(map[string]interface{})
        if !ok {
            continue
        }
        path, ok := thing["$path"].(string)
        if !ok {
            continue
        }
        fmt.Println(name, className, k, path)
    }
    return nil
}

https://go.dev/play/p/9GFpccjNQZY

相关问题