Getting invalid operation: mymap["title"] (type interface {} does not support indexing) when trying to index a map
I have data that's in a map, and I want to index into the map by key to get a value.
mdi, err := page.Metadata()
fmt.Println(mdi["title"])
However I keep getting the error message invalid operation: mdi["title"] (type interface {} does not support indexing)
. I am confused, because the data is a map and I should be able to index into it to get the value. In case the type wasn't clear, I also tried to cast the value to a string:
title, ok := mdi["title"].(string)
checkOk(ok)
fmt.Println(title)
However, I got the same error message. What am I doing wrong?
Solution 1:
The data type here was the key. mdi
was not actually a map, but an interface{}
, which could be anything - a map, a string, an int. You need to assert it to a map with expected key/value types first, or do the awkward case
switch outlined in JSON and Go.
mdi, err := page.Metadata()
md, ok := mdi.(map[string]interface{})
fmt.Println(md["title"])
Solution 2:
I'm not sure if you have control over what page.Metadata
does, but if you do, a better way is available for this situation. Say your code looks like this:
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")
}
You'd get the same error you got. But you can change it to this:
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")
}
Then whenever you need to index, you just call the appropriate method depending on what you are wanting to return. You can also add Slice if need be []interface{}
, and further methods from what I put, for example if you need to return integer. Finally, if you want to check if Map contains key, you can do this:
if m["title"] != nil {
s := m.S("title")
println(s == "Stack Overflow")
}