为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
拉丁的传说 2023-07-31 15:31:05
我正在处理 类型的数据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 mainimport "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}
查看完整描述

2 回答

?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

根据对该问题的评论,目标是在最深层嵌套的映射中设置一个值。


使用以下函数查找最大嵌套级别的映射。如果最大嵌套级别有多个映射,则此函数返回这些映射中的任意一个。


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

在操场上运行它



查看完整回答
反对 回复 2023-07-31
?
繁星coding

TA贡献1797条经验 获得超4个赞

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。)


查看完整回答
反对 回复 2023-07-31
  • 2 回答
  • 0 关注
  • 428 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信