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 callReadStruct()with that, that won't be a pointer and thus you mustn't callElem()on that.So do it like this:
Next, since you start
ReadStruct()by callingreflect.ValueOf(), that assumes you have to pass non-reflect values toReadStruct()(that is, not values of typereflect.Value).But when you iterate over the fields, calling
Value.Field(), you get areflect.Valuewrapping the field. You have to callValue.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, andValue.Index()to get the ith element of the slice.Here's the corrected version of your traversal function:
Testing it:
Output (try it on the Go Playground):
Note: By using recursive calls, you are extracting and re-acquiring
reflect.Valuevalues. It would be more efficient to always work withreflect.Values, so you can avoid these unnecessary calls.This is how you could do that:
This will output the same. Try this one on the Go Playground.