golang等同于将任何JSON转换为Python中的标准dict?

时间:2015-03-04 16:39:42

标签: json dictionary types go

在Python中你可以这样做:

r = requests.get("http://wikidata.org/w/api.php", params=params)
data = r.json()

现在data是一个dict或哈希表(同样,我不需要事先定义dict的结构),我可以通过执行数据[“实体”],数据来访问键的值[“实体”] [“Q12”]等。

我怎样才能在golang中这样做?到目前为止,我有这个:

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

这给了我编译错误:invalid operation: data["entities"] (index of type interface {})

那么var data应该是什么类型?我是否需要事先为JSON定义结构,还是可以在不修改代码的情况下处理任何JSON文件/流?

2 个答案:

答案 0 :(得分:23)

如果您需要字典,请使用转到类型map[string]interface{}map string个键和任意类型的值):

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",那么当您访问内部地图时,您可以使用{{ 3}}将它作为另一个地图:

innermap, ok := data["innermap"].(map[string]interface{})
// If ok, innermap is of type map[string]interface{}
// and you can refer to its elements.

答案 1 :(得分:0)

我更喜欢添加类型声明,这样你就可以添加方法来简化 类型断言:

package main

import (
   "encoding/json"
   "log"
   "net/http"
   "net/url"
)

type Map map[string]interface{}

func (m Map) M(s string) Map {
   return m[s].(map[string]interface{})
}

func (m Map) N(s string) float64 {
   return m[s].(float64)
}

func main() {
   v := url.Values{}
   v.Set("action", "wbgetentities")
   v.Set("format", "json")
   v.Set("ids", "Q24871")
   resp, e := http.Get("https://www.wikidata.org/w/api.php?" + v.Encode())
   if e != nil {
      log.Fatal(e)
   }
   data := Map{}
   json.NewDecoder(resp.Body).Decode(&data)
   pageid := data.M("entities").M("Q24871").N("pageid")
   println(pageid == 28268)
}

https://golang.org/ref/spec#Type_declarations