01A*_*key 7 json dictionary go
我正在做一些非常基本的JSON操作来学习一些Go,并且它有效,除了一件事似乎关闭,我必须编写分配.(map[string]interface{})
和.([]interface{})
访问JSON中的条目,特别是如果它们是孩子的孩子等等.
看到这里(也在Go Playground:https://play.golang.org/p/Wd-pzHqTsU):
package main
import (
"fmt"
"encoding/json"
)
func main() {
JSON := []byte(`{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]}`)
fmt.Printf("%s\n", JSON)
var d map[string]interface{}
json.Unmarshal(JSON, &d)
fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"])
d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"] = "change1"
fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"])
JSON, _ = json.Marshal(d)
fmt.Printf("%s\n", JSON)
}
Run Code Online (Sandbox Code Playgroud)
哪个回报:
{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]}
c3val1
change1
{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"change1"}}]}
Run Code Online (Sandbox Code Playgroud)
现在在Python中我只是直接访问键/值而不是定义我每次访问的类型,而不是fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"])
你做的print d["key3"][0]["c2key1"]["c3key1"]
Python示例:
import json
JSON = '{"key3": [{"c2key1": {"c3key1": "c3val1"}}], "key2": {"c1key1": "c1val1"}, "key1": "val1"}'
print JSON
d = json.loads(JSON)
print d["key3"][0]["c2key1"]["c3key1"]
d["key3"][0]["c2key1"]["c3key1"] = "change1"
print d["key3"][0]["c2key1"]["c3key1"]
JSON = json.dumps(d)
print JSON
Run Code Online (Sandbox Code Playgroud)
我在Go中这样做了吗?如果是这样,这个设计的原因是什么?或者如果没有,我该怎么办?
icz*_*cza 12
前言:我对以下解决方案进行了优化和改进,并在此处将其作为库发布:github.com/icza/dyno
.
最干净的方法是创建为struct
JSON建模的预定义类型(结构),并解组为该类型的值,并且您可以使用Selectors(对于struct
类型)和Index表达式(对于地图和切片)简单地引用元素.
但是,如果您的输入不是预定义的结构,我建议您使用以下2个辅助函数:get()
和set()
.第一个访问(返回)由任意路径(string
映射键和/或int
切片索引列表)指定的任意元素,第二个更改(设置)由任意路径指定的值(这些辅助函数的实现在最后的答案).
您只需在项目/应用程序中包含这两个函数.
现在使用这些帮助程序,您要执行的任务变得如此简单(就像python解决方案一样):
fmt.Println(get(d, "key3", 0, "c2key1", "c3key1"))
set("NEWVALUE", d, "key3", 0, "c2key1", "c3key1")
fmt.Println(get(d, "key3", 0, "c2key1", "c3key1"))
Run Code Online (Sandbox Code Playgroud)
输出:
change1
NEWVALUE
Run Code Online (Sandbox Code Playgroud)
在Go Playground上试用您修改过的应用程序.
注 - 进一步简化:
您甚至可以将路径保存在变量中并重复使用它以进一步简化上述代码:
path := []interface{}{"key3", 0, "c2key1", "c3key1"}
fmt.Println(get(d, path...))
set("NEWVALUE", d, path...)
fmt.Println(get(d, path...))
Run Code Online (Sandbox Code Playgroud)
和的实现get()
,并set()
在下面.注意:省略检查路径是否有效.此实现使用Type开关:
func get(m interface{}, path ...interface{}) interface{} {
for _, p := range path {
switch idx := p.(type) {
case string:
m = m.(map[string]interface{})[idx]
case int:
m = m.([]interface{})[idx]
}
}
return m
}
func set(v interface{}, m interface{}, path ...interface{}) {
for i, p := range path {
last := i == len(path)-1
switch idx := p.(type) {
case string:
if last {
m.(map[string]interface{})[idx] = v
} else {
m = m.(map[string]interface{})[idx]
}
case int:
if last {
m.([]interface{})[idx] = v
} else {
m = m.([]interface{})[idx]
}
}
}
}
Run Code Online (Sandbox Code Playgroud)