英文:
What's the golang equivalent of converting any JSON to standard dict in Python?
问题
在Python中,你可以这样做:
import requests
r = requests.get("http://wikidata.org/w/api.php", params=params)
data = r.json()
现在,data
是一个字典或哈希表(而且,我不需要事先定义字典的结构),我可以通过data["entities"]
、data["entities"]["Q12"]
等方式访问键的值。
在Go语言中,你可以这样做:
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
resp, err := http.Get("http://wikidata.org/w/api.php?" + v.Encode())
if err != nil {
// 处理错误
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
var data map[string]interface{}
decodeErr := decoder.Decode(&data)
if decodeErr != nil {
// 处理错误
}
fmt.Println(data["entities"], data["entities"].(map[string]interface{})["Q"+id])
}
这样做会给你一个编译错误:invalid operation: data["entities"] (index of type interface {})
。
所以,var data
应该是map[string]interface{}
类型。你需要定义一个结构来处理JSON文件/流,还是可以在不修改代码的情况下处理任何JSON文件/流呢?
英文:
In Python you can do something like this:
r = requests.get("http://wikidata.org/w/api.php", params=params)
data = r.json()
And now data
is a dict or hash table (also, I did not need to define beforehand the structure of the dict), and I can access values of keys by doing data["entities"], data["entities"]["Q12"], etc.
How would I do this in golang? So far I have this:
resp, err := http.Get("http://wikidata.org/w/api.php?"+v.Encode())
if err != nil {
// handle error
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
var data interface{}
decodeErr := decoder.Decode(&data)
if decodeErr != nil {
// handle error
}
fmt.Println(data["entities"], data["entities"]["Q"+id])
Which gives me the compile error: invalid operation: data["entities"] (index of type interface {})
So what type should var data
be? And do I need to define a structure to the JSON beforehand or is it possible to handle any JSON file/stream without modifying the code?
答案1
得分: 33
如果你想要一个字典,可以使用Go语言中的map[string]interface{}
类型(它是一个具有string
键和任意类型值的map
):
var data map[string]interface{}
然后你可以像这样引用它的元素:
data["entities"]
看看这个例子:
s := `{"text":"I'm a text.","number":1234,"floats":[1.1,2.2,3.3],
"innermap":{"foo":1,"bar":2}}`
var data map[string]interface{}
err := json.Unmarshal([]byte(s), &data)
if err != nil {
panic(err)
}
fmt.Println("text =", data["text"])
fmt.Println("number =", data["number"])
fmt.Println("floats =", data["floats"])
fmt.Println("innermap =", data["innermap"])
innermap, ok := data["innermap"].(map[string]interface{})
if !ok {
panic("inner map is not a map!")
}
fmt.Println("innermap.foo =", innermap["foo"])
fmt.Println("innermap.bar =", innermap["bar"])
fmt.Println("The whole map:", data)
输出结果:
text = I'm a text.
number = 1234
floats = [1.1 2.2 3.3]
innermap = map[foo:1 bar:2]
innermap.foo = 1
innermap.bar = 2
The whole map: map[text:I'm a text. number:1234 floats:[1.1 2.2 3.3]
innermap:map[foo:1 bar:2]]
在Go Playground上试一试。
注意:
基本上,如果你的字典是多层的(即map
包含另一个map
),就像上面例子中的"innermap"
一样,当你访问内部的字典时,你可以使用类型断言将其作为另一个字典:
innermap, ok := data["innermap"].(map[string]interface{})
// 如果 ok 为 true,innermap 的类型是 map[string]interface{}
// 你可以引用它的元素。
英文:
If you want a dictionary, use the Go type map[string]interface{}
(which is a map
with string
keys and values of any type):
var data map[string]interface{}
And then you can refer to its elements like:
data["entities"]
See this example:
s := `{"text":"I'm a text.","number":1234,"floats":[1.1,2.2,3.3],
"innermap":{"foo":1,"bar":2}}`
var data map[string]interface{}
err := json.Unmarshal([]byte(s), &data)
if err != nil {
panic(err)
}
fmt.Println("text =", data["text"])
fmt.Println("number =", data["number"])
fmt.Println("floats =", data["floats"])
fmt.Println("innermap =", data["innermap"])
innermap, ok := data["innermap"].(map[string]interface{})
if !ok {
panic("inner map is not a map!")
}
fmt.Println("innermap.foo =", innermap["foo"])
fmt.Println("innermap.bar =", innermap["bar"])
fmt.Println("The whole map:", data)
Output:
text = I'm a text.
number = 1234
floats = [1.1 2.2 3.3]
innermap = map[foo:1 bar:2]
innermap.foo = 1
innermap.bar = 2
The whole map: map[text:I'm a text. number:1234 floats:[1.1 2.2 3.3]
innermap:map[foo:1 bar:2]]
Try it on the Go Playground.
Notes:
Basically if your map is multi-level (the map
contains another map
) like the "innermap"
in the above example, when you access the inner map, you can use Type assertion to have it as another map:
innermap, ok := data["innermap"].(map[string]interface{})
// If ok, innermap is of type map[string]interface{}
// and you can refer to its elements.
答案2
得分: 3
我更喜欢添加类型声明,这样你就可以添加方法来简化类型断言:
package main
type mapType map[string]interface{}
func (t mapType) m(s string) mapType {
return t[s].(map[string]interface{})
}
func (t mapType) f(s string) float64 {
return t[s].(float64)
}
示例:
package main
import (
"encoding/json"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "http://wikidata.org/w/api.php", nil)
if err != nil {
panic(err)
}
q := req.URL.Query()
q.Set("action", "wbgetentities")
q.Set("format", "json")
q.Set("ids", "Q24871")
req.URL.RawQuery = q.Encode()
res, err := new(http.Client).Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var t mapType
json.NewDecoder(res.Body).Decode(&t)
println(t.m("entities").m("Q24871").f("pageid") == 28268)
}
https://golang.org/ref/spec#Type_declarations
英文:
I prefer to add a type declaration, that way you can add methods to simplify the
type assertions:
package main
type mapType map[string]interface{}
func (t mapType) m(s string) mapType {
return t展开收缩.(map[string]interface{})
}
func (t mapType) f(s string) float64 {
return t展开收缩.(float64)
}
Example:
package main
import (
"encoding/json"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "http://wikidata.org/w/api.php", nil)
if err != nil {
panic(err)
}
q := req.URL.Query()
q.Set("action", "wbgetentities")
q.Set("format", "json")
q.Set("ids", "Q24871")
req.URL.RawQuery = q.Encode()
res, err := new(http.Client).Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var t mapType
json.NewDecoder(res.Body).Decode(&t)
println(t.m("entities").m("Q24871").f("pageid") == 28268)
}
<https://golang.org/ref/spec#Type_declarations>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论