【问题标题】:Getting invalid operation: mymap["title"] (type interface {} does not support indexing) when trying to index a map获取无效操作:mymap["title"](类型接口 {} 不支持索引)尝试索引地图时
【发布时间】:2014-10-02 13:19:51
【问题描述】:

我有地图中的数据,我想通过键索引到地图中以获取值。

mdi, err := page.Metadata()
fmt.Println(mdi["title"])

但是我不断收到错误消息invalid operation: mdi["title"] (type interface {} does not support indexing)。我很困惑,因为数据是一张地图,我应该能够对其进行索引以获得价值。如果类型不清楚,我还尝试将值转换为字符串:

title, ok := mdi["title"].(string)
checkOk(ok)
fmt.Println(title)

但是,我收到了相同的错误消息。我做错了什么?

【问题讨论】:

    标签: map go


    【解决方案1】:

    这里的数据类型是关键。 mdi 实际上不是一个映射,而是一个interface{},它可以是任何东西——映射、字符串、整数。您需要先将其断言到具有预期键/值类型的映射,或者执行JSON and Go 中概述的尴尬case 开关。

    mdi, err := page.Metadata()
    md, ok := mdi.(map[string]interface{})
    fmt.Println(md["title"])
    

    【讨论】:

    • 这不是强制转换而是类型断言。
    • @DaveC 你能否详细解释一下This is not a cast but a type assertion。为什么 golang 需要类型断言,如果不需要强制转换,为什么不直接给出结果。如果未能执行所需的强制转换,它可能会出错。但是,如果不需要casting,为什么还需要type assertion
    • 我认为您来自动态类型语言。从您发布的代码中我可以理解,似乎编写 Metadata() 是为了返回 interface{} 而不是地图。如果您将其更改为返回地图,您的代码将正常工作。它是接口,然后调用者必须首先知道返回值的实际类型,以便它可以允许对值进行特定于该类型的操作。默认情况下,任何类型都是接口类型,因此您不能对接口执行任何特定于类型的操作。 @PrakashPandey
    【解决方案2】:

    我不确定您是否可以控制 page.Metadata 的操作,但如果您可以控制,则可以使用更好的方法来应对这种情况。假设您的代码如下所示:

    package main
    
    import (
       "encoding/json"
       "log"
    )
    
    func Metadata() (interface{}, error) {
       y := []byte(`{"metadata": {"title": "Stack Overflow"}}`)
       var m map[string]interface{}
       e := json.Unmarshal(y, &m)
       if e != nil {
          return nil, e
       }
       return m["metadata"], nil
    }
    
    func main() {
       m, e := Metadata()
       if e != nil {
          log.Fatal(e)
       }
       s := m["title"]
       println(s == "Stack Overflow")
    }
    

    你会得到同样的错误。但是你可以把它改成这样:

    type Map map[string]interface{}
    
    func (m Map) M(s string) Map {
       return m[s].(map[string]interface{})
    }
    
    func (m Map) S(s string) string {
       return m[s].(string)
    }
    
    func Metadata() (Map, error) {
       y := []byte(`{"metadata": {"title": "Stack Overflow"}}`)
       var m Map
       e := json.Unmarshal(y, &m)
       if e != nil {
          return nil, e
       }
       return m.M("metadata"), nil
    }
    
    func main() {
       m, e := Metadata()
       if e != nil {
          log.Fatal(e)
       }
       s := m.S("title")
       println(s == "Stack Overflow")
    }
    

    然后,每当您需要索引时,您只需根据要返回的内容调用适当的方法。如果需要[]interface{},您还可以添加 Slice,以及我提出的其他方法,例如,如果您需要返回整数。最后,如果你想检查 Map 是否包含 key,你可以这样做:

    if m["title"] != nil {
       s := m.S("title")
       println(s == "Stack Overflow")
    }
    

    【讨论】:

      猜你喜欢
      • 2018-09-16
      • 1970-01-01
      • 2016-07-27
      • 2018-05-24
      • 2014-09-14
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 2012-05-24
      相关资源
      最近更新 更多