I have a function which accept all type of struct as interface. If I try to print
s.Index(i)
It gives me the values. However once I append it into
allRows []interface{}
and print it out. Instead of value I am getting the type of struct that I passed the function.
As an exapmle.
fmt.Println("AllRows",allRows)
[<adminPanel.allBeaconInfo Value> <adminPanel.allBeaconInfo Value>
<adminPanel.allBeaconInfo Value> <adminPanel.allBeaconInfo Value>
<adminPanel.allBeaconInfo Value>]
func pagination(c *gin.Context, st interface{}) {
var allRows []interface{}
switch reflect.TypeOf(st).Kind() {
case reflect.Slice:
s := reflect.ValueOf(st)
for i := 0; i < s.Len(); i++ {
allRows=append(allRows,s.Index(i))
fmt.Println(allRows)
}
}
fmt.Println("AllRows",allRows)
The expression s.Index(i) evaluates to a reflect.Value containing the actual slice element. Call Value.Interface() to get the actual slice element.
var allRows []interface{}
switch reflect.TypeOf(st).Kind() {
case reflect.Slice:
s := reflect.ValueOf(st)
for i := 0; i < s.Len(); i++ {
allRows=append(allRows,s.Index(i).Interface())
fmt.Println(allRows)
}
}
Related
Below is a method which uses reflect package to modify fields of a struct ,this works for a specific struct type
func modify(obj Car) interface{} {
ty := reflect.TypeOf(obj)
for i := 0; i < ty.NumField(); i++ {
rval := reflect.Indirect(reflect.ValueOf(&obj))
field := rval.Field(i)
fieldType := field.Kind()
switch fieldType {
case reflect.String:
field.SetString("")
case reflect.Int:
field.SetInt(0)
case reflect.Ptr:
field.Set(reflect.ValueOf(nil))
}
}
return obj
}
modifying the signature to
func modify(obj interface{}) interface{} {
results in
panic: reflect: call of reflect.Value.Field on interface Value
at line
field := rval.Field(i)
https://go.dev/play/p/pGfKtIg5RUp
It works with the signature
func modify(obj Car) interface{} {
https://go.dev/play/p/31Oh6WLmlGP
Why is the compile time type modifying the behaviour ?
The goal here is to mask certain fields based on struct tags .It could wrap an endpoint and the input and output to the method being wrapped could be struct or pointer so in above case both calls should work
modify(car)
modify(&car)
This is how it works for both value and pointer types
func modify(obj interface{}) interface{} {
rv := reflect.ValueOf(obj)
trv := reflect.TypeOf(obj)
value := reflect.New(rv.Type())
if rv.Kind() == reflect.Pointer {
rv = reflect.ValueOf(obj).Elem()
trv = reflect.TypeOf(obj).Elem()
value = reflect.New(rv.Type())
}
for i := 0; i < rv.NumField(); i++ {
field := rv.Field(i)
fieldType := field.Kind()
v := value.Elem().Field(i)
tag, _ := trv.Field(i).Tag.Lookup("es")
if len(tag) != 0 {
switch fieldType {
case reflect.String:
v.SetString(tag)
case reflect.Int:
v.SetInt(0)
case reflect.Ptr:
v.Set(reflect.ValueOf(nil))
}
} else {
v.Set(field)
}
}
return value
}
https://go.dev/play/p/C1pqw_UbPcG
I write a recursive function that iterate over deep nested struct like the following:
type Container struct {
Name string
Items []Item
}
type Item struct {
Name string
Info Info
Vals []string
}
// recursively reads nested struct, prints string values
func ReadStruct(st interface{}) {
val := reflect.ValueOf(st).Elem()
for i := 0; i < val.NumField(); i++ {
fmt.Println(val.Type().Field(i).Type.Kind())
switch val.Type().Field(i).Type.Kind() {
case reflect.Struct:
ReadStruct(val.Field(i)) // panic: call of reflect.Value.Elem on struct Value
case reflect.Slice:
// How to iterate over the reflect.Slice?
case reflect.String:
fmt.Printf("%v=%v", val.Type().Field(i).Name, val.Field(i))
}
}
how to get access to inner objects (slices, structs) to work with them using reflect?
to iterate over slice i tried to use:
for i:= 0; i < val.Field(i).Slice(0, val.Field(i).Len()); i++ { //error: reflect.Value doesnt support indexing
//some work
}
Couple of errors in your code.
First, you only have to call Value.Elem() if the passed value is a pointer. When you iterate over the fields and you find a field of struct type, and you recursively call ReadStruct() with that, that won't be a pointer and thus you mustn't call Elem() on that.
So do it like this:
val := reflect.ValueOf(st)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
Next, since you start ReadStruct() by calling reflect.ValueOf(), that assumes you have to pass non-reflect values to ReadStruct() (that is, not values of type reflect.Value).
But when you iterate over the fields, calling Value.Field(), you get a reflect.Value wrapping the field. You have to call Value.Interface() to extract the non-reflect value form it, to be passed in recursive calls.
To iterate over slices, simply use Value.Len() to get the slice length, and Value.Index() to get the ith element of the slice.
Here's the corrected version of your traversal function:
// I used this type as you didn't post it in your question.
type Info struct {
Key, Value string
}
func ReadStruct(st interface{}) {
val := reflect.ValueOf(st)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
// fmt.Println(val.Type().Field(i).Type.Kind())
f := val.Field(i)
switch f.Kind() {
case reflect.Struct:
ReadStruct(f.Interface())
case reflect.Slice:
for j := 0; j < f.Len(); j++ {
ReadStruct(f.Index(i).Interface())
}
case reflect.String:
fmt.Printf("%v=%v\n", val.Type().Field(i).Name, val.Field(i).Interface())
}
}
}
Testing it:
c := &Container{
Name: "c1",
Items: []Item{
{
Name: "i1",
Info: Info{Key: "k1", Value: "v1"},
},
{
Name: "i2",
Info: Info{Key: "k2", Value: "v2"},
},
},
}
ReadStruct(c)
Output (try it on the Go Playground):
Name=c1
Name=i2
Key=k2
Value=v2
Name=i2
Key=k2
Value=v2
Note: By using recursive calls, you are extracting and re-acquiring reflect.Value values. It would be more efficient to always work with reflect.Values, so you can avoid these unnecessary calls.
This is how you could do that:
func ReadStruct(st interface{}) {
readStruct(reflect.ValueOf(st))
}
func readStruct(val reflect.Value) {
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
// fmt.Println(val.Type().Field(i).Type.Kind())
f := val.Field(i)
switch f.Kind() {
case reflect.Struct:
readStruct(f)
case reflect.Slice:
for j := 0; j < f.Len(); j++ {
readStruct(f.Index(i))
}
case reflect.String:
fmt.Printf("%v=%v\n", val.Type().Field(i).Name, val.Field(i))
}
}
}
This will output the same. Try this one on the Go Playground.
How to go through all fields in a struct and edit/validate them on the fly?
Example:
func UrlEncodeStruct(s interface{}) {
r := reflect.ValueOf(obj)
for i := 0; i < r.NumField(); i++ {
value := r.Field(i).String()
value = url.QueryEscape(value)
r.Field(i).SetString(value)
}
}
To modify the struct value in the caller, change the function to take a pointer to the struct value. Otherwise, the posted function is correct for a struct containing only exported string fields.
func UrlEncodeStruct(s interface{}) {
r := reflect.ValueOf(s).Elem() // <-- note call to Elem() here
for i := 0; i < r.NumField(); i++ {
value := r.Field(i).String()
value = url.QueryEscape(value)
r.Field(i).SetString(value)
}
}
Call it like this:
var s someStructType
UrlEncodeStruct(&s)
playground example
I need to check if interface{} is an array and create corresponding slice if it is. Unfortunately I do not know array length in advance.
For example:
import (
"reflect"
)
func AnythingToSlice(a interface{}) []interface{} {
rt := reflect.TypeOf(a)
switch rt.Kind() {
case reflect.Slice:
slice, ok := a.([]interface{})
if ok {
return slice
}
// it works
case reflect.Array:
// return a[:]
// it doesn't work: cannot slice a (type interface {})
//
array, ok := a.([reflect.ValueOf(a).Len()]interface{})
// :-((( non-constant array bound reflect.ValueOf(a).Len()
if ok {
return array[:]
}
}
return []interface{}(a)
}
An explicit type is required in a type assertion. The type cannot be constructed through reflection.
Unless the argument is a []interface{}, the slice or array must be copied to produce a []interface{}.
Try this:
func AnythingToSlice(a interface{}) []interface{} {
v := reflect.ValueOf(a)
switch v.Kind() {
case reflect.Slice, reflect.Array:
result := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
result[i] = v.Index(i).Interface()
}
return result
default:
panic("not supported")
}
}
https://play.golang.org/p/3bXxnHOK8_
I want to pass a struct object to a function & be able to access its pointer value from that function. I am not able to understand why the following is resulting in error.
func GetStructFieldPointers(u interface{}, jsonFields []string) []interface{} {
structVal := reflect.ValueOf(&u).Elem()
structType := reflect.TypeOf(u)
numberOfFields := structVal.NumField() // getting error here reflect:
// call of reflect.Value.NumField
// on interface Value
numberOfJSONFields := len(jsonFields)
res := make([]interface{}, numberOfJSONFields)
fmt.Println(jsonFields)
for fieldIndex, field := range jsonFields {
for i := 0; i < numberOfFields; i++ {
if structType.Field(i).Tag.Get("json") == field {
valueField := structVal.Field(i)
res[fieldIndex] = valueField.Addr().Interface()
}
}
}
return res
}
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
}
user := User{}
res := GetStructFieldPointers(user, []string{"id", "name"})
To make this work, I had to make structType as a parameter like following:
func GetStructFieldPointers(u interface{}, structType reflect.Type, jsonFields []string) []interface{} {
structVal := reflect.ValueOf(u).Elem()
// structType := reflect.TypeOf(u)
numberOfFields := structVal.NumField()
numberOfJSONFields := len(jsonFields)
res := make([]interface{}, numberOfJSONFields)
fmt.Println(jsonFields)
for fieldIndex, field := range jsonFields {
for i := 0; i < numberOfFields; i++ {
if structType.Field(i).Tag.Get("json") == field {
valueField := structVal.Field(i)
res[fieldIndex] = valueField.Addr().Interface()
}
}
}
return res
}
user := User{}
res := GetStructFieldPointers(&user, reflect.TypeOf(user), []string{"id", "name"})
I like to know how to pass User{} as a parameter & use in both reflect.ValueOf & reflect.TypeOf calls.
On this line: structVal := reflect.ValueOf(&u).Elem() you're taking the address of an interface (the argument of your func) and not an address to the interface's underlying value, and then you're passing the pointer to ValueOf, so the .Elem() call returns the "elem value" to which the pointer points to, which is the interface, not struct.
If you know for a fact that the passed in value is a struct and not a pointer, all you need is this: structVal := reflect.ValueOf(u).
If a pointer was passed to your func, eg GetStructFieldPointers(&u, ... then this is what you want: structVal := reflect.ValueOf(u).Elem().
But also you can handle both cases by checking the value's kind.
rv := reflect.ValueOf(u)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if rv.Kind() == reflect.Struct {
fmt.Println(rv.NumField())
}
https://play.golang.org/p/9F9LNnwEaH
Update:
Took a better look at your code... If you want to be able to get the addresses of your struct's fields, you need to pass a pointer to the struct as the argument, or else those fields are going to be unaddressable.
https://play.golang.org/p/RaA2rau3s-