Get Interface Field Values From an Interface Without Declaring Structure in Golang

27,738

You can use type assertion instead of reflection. It is generally better to avoid reflection whenever you can.

m, ok := t.(map[string]interface{})
if !ok {
    return fmt.Errorf("want type map[string]interface{};  got %T", t)
}
for k, v := range m {
    fmt.Println(k, "=>", v)
}

If you really want to use reflection, you can do something like this:

s := reflect.ValueOf(t)
for _, k := range s.MapKeys() {
    fmt.Println(s.MapIndex(k))
}

Update to reply to your latest update

It does not return what you expect because it returns a reflect.Value. If you want an integer value, you have to use ratingsCount.Int().

But as I said before, don't use reflection. Use the first solution with type assertion and just get the count with m["count"].

I posted working example there using type assertion: https://play.golang.org/p/9gzwtJIfd7

Share:
27,738
Amandeep kaur
Author by

Amandeep kaur

Updated on July 09, 2022

Comments

  • Amandeep kaur
    Amandeep kaur almost 2 years

    I am trying to get field values from an interface in Golang. The interface is initially an empty interface which is getting its values from a database result. The DB query is working fine.

    The only thing I need is that I need to get the field value of the interface. Here is my code:

    s := reflect.ValueOf(t)
        for i := 0; i < s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
    

    where t is an interface having following values:

    map[id:null count:1]
    

    I want value of "count" like simply 1.

    My problem is that the Index() method is returning a panic because it needs a struct and I dont have any struct here. So what should I do to get interface value? Is there any solution to iterate over an interface to get field values with or without Golang's reflection package?

    Edit

    After getting the value for count I need to parse it to json.

    Here is my code:

    type ResponseControllerList struct{
        Code            int             `json:"code"`
        ApiStatus       int             `json:"api_status"`
        Message         string          `json:"message"`
        Data            interface{}     `json:"data,omitempty"`
        TotalRecord     interface{}     `json:"total_record,omitempty"`
    }
    response := ResponseControllerList{}
    ratingsCount := reflect.ValueOf(ratingsCountInterface).MapIndex(reflect.ValueOf("count"))
    fmt.Println(ratingsCount)
    
    response = ResponseControllerList{
                    200,
                    1,
                    "success",
                    nil,
                    ratingsCount,
                }
    GetResponseList(c, response)
    
    func GetResponseList(c *gin.Context, response ResponseControllerList) {
        c.JSON(200, gin.H{
            "response": response,
        })
    }
    

    The above code is being used to get the ratingCount in JSON format to use this response as API response. In this code, I am using the GIN framework to make HTTP request to API.

    Now the problem is that when I am printing the variable ratingsCount, its displaying the exact value of count in terminal what I need. But when I am passing it to JSON, the same variable gives me the response like:

    {
        "response": {
            "code": 200,
            "api_status": 1,
            "message": "Success",
            "total_record": {
                "flag": 148
            }
        }
    }
    

    What is the way to get the count's actual value in JSON ?

  • Amandeep kaur
    Amandeep kaur over 6 years
    thanks for replying to my question. I have checked your solution and its working fine to get the count value. But I have edited my post to get this count value in json. Please check and provide the solution if you have any.
  • Amandeep kaur
    Amandeep kaur over 6 years
    Well @R3v4n, neither type assertion nor ratingsCount.Int() is working. When I do type assertion it returns an empty map. Also ratingsCount.Int() is giving panic saying reflect: call of reflect.Value.Int on interface Value.
  • R3v4n
    R3v4n over 6 years
    @Amandeepkaur: I edited my reply with a link to a working example on the Go playground. Forget about the reflection, it really makes things more complicated for no gain. Let's focus on my solution that uses type assertion. If the map is empty, it is probably the value of ratingsCountInterface that is not what you expect. Can you paste the entire source code?
  • Amandeep kaur
    Amandeep kaur over 6 years
    I have tried your both code snippets. but in both case its returning empty map. And I think there is no logic difference between the two. The interface I am passing to get type assertion is a bson.M type interface (for mongodb). Now what should I do ?
  • R3v4n
    R3v4n over 6 years
    If you are passing a bson.M it is not an interface, it is a map[string]interface{}: godoc.org/labix.org/v2/mgo/bson#M therefore, there is no need for type assertion. You should be able to directly access the value. Can you paste all the relevant parts of you source code?
  • Amandeep kaur
    Amandeep kaur over 6 years
    If it is a map and I directly access the index of a map, it gives the following error: invalid operation: RatingInterface["count"] (type interface {} does not support indexing). So I can not directly access the bson map.
  • R3v4n
    R3v4n over 6 years
    At some point in your code, the bson.M is converted into an interface{}. If you can avoid this, that would be the best option. Using interface{} break the type checking at compilation time. If you can't, instead of using type assertion on type map[string]interface{} you have to do type assertion with the type bson.M, like this: ratingsCount, ok := v.(bson.M)
  • Amandeep kaur
    Amandeep kaur over 6 years
    I got it. You are right, its type assertion should be to bson.M type. Your answer to use type assertion instead of reflect solved my issue. I used type assertion bson.M to get direct value from map. Thanks @R3v4n, please update your answer so that I can mark this question resolved.