简体   繁体   中英

Error: interface conversion interface {} is []interface {}, not map[string]interface {}

I am building a project that takes a term from the user and then performs a google search and returns a list of titles in json format.

I am using the serpwow API to perform the google search and am trying to parse the response.

However I am getting the error that states:

panic: interface conversion: interface {} is []interface {}, not map[string]interface {}.

I have looked through various forms and have tried to learn how mapping works but I am not sure why in this case, my mapping is not working. The table for organic results looks like this:

"organic_results": [
    {
      "position": 1,
      "title": "The 10 Best Pizza Places in Dublin - TripAdvisor",
      "link": "https://www.tripadvisor.ie/Restaurants-g186605-c31-Dublin_County_Dublin.html",
      "domain": "www.tripadvisor.ie",
      "displayed_link": "https://www.tripadvisor.ie › ... › County Dublin › Dublin",
      "snippet": "Best Pizza in Dublin, County Dublin: Find TripAdvisor traveller reviews of Dublin Pizza places and search by price, location, and more.",
      "prerender": false,
      "snippet_matched": [
        "Pizza",
        "Pizza"
      ],
      "cached_page_link": "https://webcache.googleusercontent.com/search?q=cache:OS-Ar9hB_ngJ:https://www.tripadvisor.ie/Restaurants-g186605-c31-Dublin_County_Dublin.html+&cd=4&hl=en&ct=clnk&gl=ie",
      "related_page_link": "https://www.google.com/search?q=related:https://www.tripadvisor.ie/Restaurants-g186605-c31-Dublin_County_Dublin.html+pizza&tbo=1&sa=X&ved=2ahUKEwicjYKvvNjmAhVoSBUIHa9MBhcQHzADegQIARAH",
      "block_position": 2
    },

and here is a snip of my code:

package main

import (
    "fmt"
    "strings"
    serpwow "github.com/serpwow/google-search-results-golang"
)

func main() {
    // set API key
    apiKey := "Key_Hidden"

    //read term to search
    fmt.Print("What term would you like to search in google? ")
    var term string
    fmt.Scanln(&term)

    // set up our search parameters
    parameters := map[string]interface{}{
        "q": term,
    }

    // retrieve the search results as JSON
    response, error := serpwow.GetJSON(parameters, apiKey)

    // print the response, or error, if one occurred
    if error != nil {
        fmt.Println(error)
    } else {
    //extract title from organic results
    //result := fmt.Sprintf("%v", response["organic_results"].(map[string]interface{})["title"])
    for _, item := range response["organic_results"].([]interface{}) {
        fmt.Sprintf("%v", item.(map[string]interface{})["title"])
    }
    //s := []string{result, "\n"}
    //fmt.Printf(strings.Join(s, " "))

}

} Can someone please help me figure our where my logic is wrong?

response["organic_results"] corresponds to the JSON array "organic_results", hence it is not a map[string]interface{} , but a []interface . There are multiple results, not one.

for _,item:=range respose["organic_results"].([]interface{}) {
    fmt.Printf("%v", item.(map[string]interface{})["title"])
}

As you can see in your JSON, organic_results 's value is a JSON array, not an object; each element of the array is an object. So you can't assert organic_results to map[string]interface{} because, as the error states, it's not a map, it's a []interface . You could, for example, do:

    result := fmt.Sprintf("%v", response["organic_results"].([]interface{})[0].(map[string]interface{})["title"])

But of course this will only get you the title of the first result, and it will crash if the results are empty. You'll have to think of this not as "get the title from the response" and instead as "handling zero or more results returned" - ie you'll probably want to loop over organic_results and do something with each result object.

Sometimes, reverse engineering also works, I had the same issue of not able to UnMarshall a custom made JSON file although all the types which I had defined looked very intuitive.

type ResourceConfig struct {
    ResourceType map[string]AlphabetType  `json:"resourceType"`
    RedisConfig  RedisConfigT               `json:"redisConfig"`
}

type AlphabetType struct {
    XXX  []string `json:"xxx"`
    YYY []string `json:"yyy"`
}

type RedisConfigT struct {
    Broker string     `json:"broker"`
    DB     string     `json:"db"`
}

For which the json looked like this:

{
        "resourceType": [
                {"/abcdefg": [{"xxx": ["/vrf", "/lsp", "/vpn"], "yyy": ["/fpc"]}]},
                {"/vrf": [{"xxx": [""], "yyy": ["/abcdefg"]}]},
                {"/lsp": [{"xxx": [""], "yyy": ["/abcdefg"]}]},
                {"/vpn": [{"xxx": [""], "yyy": ["/abcdefg"]}]},
                {"/fpc": [{"xxx": ["/abcdefg"], "yyy": [""]}]}
        ],
        "redisConfig": {"broker": "localhost: 6379", "db": 0}
}

When doing UnMarshall it was throwing error of not able to parse.

So I decided to form the required map programmatically first Marshal it into a json, and print it.

{"resourceType":{"/fpc":{"XXX":["/abcdefg"],"YYY":[]},
"/abcdefg":{"XXX":["/vrf","/lsp","/vpn"],"YYY":["/fpc"]},
"/abc":{"XXX":[],"YYY":["/abcdefg"]},
"/vpn":{"XXX":[],"YYY":["/abcdefg"]},
"/vrf":{"XXX":[],"YYY":["/abcdefg"]}},
"redisConfig":{"broker":"localhost:6349","db":"0"}}

Now use the same format in. the json file and UnMarshal it. It will nicely fit into the types you have defined based on which the Json was generated originally.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM