Get Interface Field Values From an Interface Without Declaring Structure in Golang
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
Amandeep kaur
Updated on July 09, 2022Comments
-
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 over 6 yearsthanks 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 over 6 yearsWell @R3v4n, neither type assertion nor
ratingsCount.Int()
is working. When I do type assertion it returns an empty map. AlsoratingsCount.Int()
is giving panic sayingreflect: call of reflect.Value.Int on interface Value
. -
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 over 6 yearsI 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 over 6 yearsIf 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 over 6 yearsIf 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 over 6 yearsAt 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 typebson.M
, like this: ratingsCount, ok := v.(bson.M) -
Amandeep kaur over 6 yearsI 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.