【问题标题】:invalid operation: type interface {} does not support indexing无效操作:type interface {} 不支持索引
【发布时间】:2018-05-24 15:58:09
【问题描述】:

我是 golang 新手,在读取嵌套的 JSON 响应时遇到问题。

var d interface{}
json.NewDecoder(response.Body).Decode(&d)
test :=d["data"].(map[string]interface{})["type"]

response.Body 看起来像这样

{
    "links": {
      "self": "/domains/test.one"
    },
    "data": {
        "type": "domains",
        "id": "test.one",
        "attributes": {
            "product": " Website",
            "package": "Professional",
            "created_at": "2016-08-19T11:37:01Z"
        }
    }
}

我得到的错误是这样的:

invalid operation: d["data"] (type interface {} does not support indexing)

【问题讨论】:

  • 这是一个不错的资源gobyexample.com/json
  • @jeff 我正在使用界面,假设我不知道响应的结构。
  • @Jeff 它可以工作,但假设我必须解析嵌套元素,这个解决方案会很复杂。你有其他解决方案吗?

标签: json dictionary go unmarshalling type-assertion


【解决方案1】:

你也可以这样做:

var inputJson string = "..."

var decoded map[string]map[string]interface{}

json.Unmarshal([]byte(inputJson), &decoded)

test := decoded["data"]["type"]

fmt.Println(test)
// output: domains

【讨论】:

    【解决方案2】:

    dinterface{} 类型,所以你不能像d["data"] 那样索引它,你需要另一个类型断言:

    test := d.(map[string]interface{})["data"].(map[string]interface{})["type"]
    fmt.Println(test)
    

    然后它将起作用。输出将是"domains"。请参阅Go Playground 上的工作示例。

    还请注意,如果您将d 声明为map[string]interface{} 类型,则可以省略第一个类型断言:

    var d map[string]interface{}
    if err := json.NewDecoder(response.Body).Decode(&d); err != nil {
        panic(err)
    }
    test := d["data"].(map[string]interface{})["type"]
    fmt.Println(test)
    

    输出是一样的。在Go Playground 上试试这个。

    如果您需要多次执行这些和类似操作,您可能会发现我的 github.com/icza/dyno 库很有用(其主要目标是帮助处理动态对象)。

    【讨论】:

    • 给像我这样的新手的提示:要理解这段代码为什么有效,应该了解Decode 的工作原理,这与unmarshal 有关。 json.Unmarshal 文档解释了它如何存储数据。
    【解决方案3】:

    你需要一些技巧来处理你的情况。
    就像使用反射一样,您可以参考 golang mongo driver mgo 中有关 bson.M 的 Marshall&&UnMarshall 代码

    使用反射解码的代码示例嵌套如下:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    func main() {
        keys := []string{"hello", "world", "dude", "kind", "cool"}
        a := make(map[string]interface{})
        a[keys[4]] = "perfect"
        b := make(map[string]interface{})
        b[keys[3]] = a
        c := make(map[string]interface{})
        c[keys[2]] = b
        d := make(map[string]interface{})
        d[keys[1]] = c
        e := make(map[string]interface{})
        e[keys[0]] = d
        fmt.Println(e)
    
        if buf, err := json.Marshal(e); nil == err {
            dd := make(map[string]interface{})
            err = json.Unmarshal(buf, &dd)
            if nil != err {
                fmt.Println("failed", err)
            }
    
            for k, v := range dd {
                travel(dd, k, v)
            }
            fmt.Println(dd)
    
        } else {
            fmt.Println("failed marshal")
        }
    }
    
    func travel(dd map[string]interface{}, key string, value interface{}) {
        vv := reflect.ValueOf(value)
        switch vv.Kind() {
        case reflect.Map:
            m := value.(map[string]interface{})
            dd[key] = m
            for k, v := range m {
                travel(m, k, v)
            }
        case reflect.String:
            dd[key] = value.(string)
        }
    }
    

    【讨论】:

    • 这个问题与BSON或Mongo无关。如果你想在这种情况下引用一些使用反射的东西,你不妨阅读 json 包的源代码,因为它实际上是相关的。
    • 我推荐阅读bson.M,因为提问者在cmets中说,nested interface{},我认为bson.M是decode nested interface{}的一个例子
    • 嵌套的处理是简单的递归。 JSON 也可以。
    • 我是新手,对 bson.M 很熟悉,很抱歉浪费您的时间。
    猜你喜欢
    • 2019-08-18
    • 2018-05-09
    • 2018-09-16
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2014-10-02
    • 2011-09-11
    相关资源
    最近更新 更多