25

I have a function as below which decodes some json data and returns it as an interface

package search

func SearchItemsByUser(r *http.Request) interface{} {

    type results struct {
        Hits             hits
        NbHits           int
        NbPages          int
        HitsPerPage      int
        ProcessingTimeMS int
        Query            string
        Params           string
    }

    var Result results

    er := json.Unmarshal(body, &Result)
    if er != nil {
        fmt.Println("error:", er)
    }
    return Result

}

I'm trying to access the data fields ( e.g. Params) but for some reasons it says that the interface has no such field. Any idea why ?

func test(w http.ResponseWriter, r *http.Request) {

    result := search.SearchItemsByUser(r)
        fmt.Fprintf(w, "%s", result.Params)
themihai
  • 7,903
  • 11
  • 39
  • 61

1 Answers1

33

An interface variable can be used to store any value that conforms to the interface, and call methods that art part of that interface. Note that you won't be able to access fields on the underlying value through an interface variable.

In this case, your SearchItemsByUser method returns an interface{} value (i.e. the empty interface), which can hold any value but doesn't provide any direct access to that value. You can extract the dynamic value held by the interface variable through a type assertion, like so:

dynamic_value := interface_variable.(typename)

Except that in this case, the type of the dynamic value is private to your SearchItemsByUser method. I would suggest making two changes to your code:

  1. Define your results type at the top level, rather than within the method body.

  2. Make SearchItemsByUser directly return a value of the results type instead of interface{}.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • I don't really see how I could define the results class (type) at the top level as it has a Hits of type hits. Am I missing something ? SearchItemsByUser doesn't seem to return an empty interface. If I print result from the test function ( fmt.Fprintf(w, "%s", result) ) I get something that looks much like the the data I need (e.g. test0 %!s(int=3) mihai/test0/0}] %!s(int=1) %!s(int=1) %!s(int=10) %!s(int=1) attributesToHighlight ) – themihai Feb 15 '14 at 10:46
  • You've defined the function to return `interface{}` -- that's the empty interface. By top level, I mean at the package level, rather than embedded inside the method. What does the `hits` type have to do with it? – James Henstridge Feb 15 '14 at 10:50
  • @mihai Of course `searchItemsByUser` returns an empty interface! You declared it like that! The value is still there, but it's "_behind_" the interface. You can still extract the value (or cast it to another interface) which is what `fmt.Fprintf` does. – Cubic Feb 15 '14 at 10:52
  • OK...it works and it's great! I didn't know I could define it at the package level. – themihai Feb 15 '14 at 11:01