在 Golang 中向嵌套的 map[string]interface{} 添加属性

我正在处理 类型的数据map[string]interface{}。它可以在 (map[string]interface{}) 类型内拥有无限数量的嵌套对象。


编辑: 此数据来自 mongodb。我不能在这里真正应用 golang 的结构,因为属性因文档而异。我想要做的就是获取最深嵌套的对象,向其添加新属性并确保之后更新整个数据对象。


data["person"] = map[string]interface{}{

    "peter": map[string]interface{}{

        "scores": map[string]interface{}{

            "calculus": 88,

            "algebra":  99,

            "golang":   89,

        },

    },

}

这些数据来自远程 API,我不知道里面的属性。我想添加的只是在最后一个对象(在本例中为“分数”)内添加新属性,并且可以说使用这个新属性(“物理”),数据将如下所示


data["person"] = map[string]interface{}{

    "peter": map[string]interface{}{

        "scores": map[string]interface{}{

            "calculus": 88,

            "algebra":  99,

            "golang":   89,

            "physics":  95,

        },

    },

}

我不确定如何将该属性添加到最后一个对象中。


我进行了递归类型检查,并且能够获取每个字段并打印其值。但是,由于映射不是引用性的,因此当我使用非复杂类型的值到达映射时,我无法向原始映射添加值。


package main


import "fmt"


func main() {


    data := make(map[string]interface{})

    data["person"] = map[string]interface{}{

        "peter": map[string]interface{}{

            "scores": map[string]interface{}{

                "calculus": 88,

                "algebra":  99,

                "golang":   89,

            },

        },

    }


    parseMap(data)

}



func parseMap(aMap map[string]interface{}) interface{} {

    var retVal interface{}


    for _, val := range aMap {

        switch val.(type) {

        case map[string]interface{}:

            retVal = parseMap(val.(map[string]interface{}))

        //case []interface{}:

        //  retVal = parseArray(val.([]interface{}))

        default:

            //here i would have done aMap["physics"] = 95 if I could access the original map by reference, but that is not possible


            retVal = aMap


        }

    }


    return retVal

}


拉丁的传说
浏览 488回答 2
2回答

收到一只叮咚

根据对该问题的评论,目标是在最深层嵌套的映射中设置一个值。使用以下函数查找最大嵌套级别的映射。如果最大嵌套级别有多个映射,则此函数返回这些映射中的任意一个。func findDeepest(m map[string]interface{}) (int, map[string]interface{}) {    depth := 0    candidate := m    for _, v := range m {        if v, ok := v.(map[string]interface{}); ok {            d, c := findDeepest(v)            if d+1 > depth {                depth = d + 1                candidate = c            }        }    }    return depth, candidate}像这样使用它在深度嵌套映射中设置一个值:_, m := findDeepest(data)m["physics"] = 95在操场上运行它。

繁星coding

map[string]interface{}尽量避免使用原始类型。Goencoding/json文件可以很好地处理字符串键控的映射,并且希望远程 API对于您正在处理的内容有某种规范。(例如,您知道您需要一个person顶级密钥并且位于层次结构中的特定点。)scores我假设远程 API 是 JSON-over-HTTP。您可以将其结构建模为type Input struct {    Person map[string]Person `json:"person"`}type Person struct {    Scores map[string]int `json:"scores"`}将json.Unmarshal()数据写入此结构后,您可以直接设置data.Person["peter"].Scores["physics"] = 95然后json.Marshal()再次得到结果。 https://play.golang.org/p/qoAVFodSvK2有一个完整的示例。如果您确实想直接操作map[string]interface{}结构,我建议将每个“级别”拆分为单独的函数调用func ParseTopLevel(data map[string]interface{}) {    switch peter := data["peter"].(type) {    case map[string]interface{}:        ParsePeter(peter)    }}map类型是通过引用传递的,因此当到达堆栈底部时可以直接设置scores["physics"] = 95。(在您的原始代码中,如果您无法按照aMap["physics"]您的建议直接设置,我会感到惊讶,尽管设置的内容相当不精确;比较https://play.golang.org/p/VuTjcjezwwU。)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go