Reputation: 33587
I'm trying to extract all of the values for a struct into a string slice.
func structValues(item Item) []string {
values := []string{}
e := reflect.ValueOf(&item).Elem()
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
I'd like to use this function with any struct, so I thought I could just change the type signature to func structValues(item interface{})
but then I got a panic:
panic: reflect: call of reflect.Value.NumField on interface Value
Working example: https://repl.it/@fny/stackoverflow61719532
Upvotes: 0
Views: 1098
Reputation: 489153
I'd like to use this function with any struct ...
You can do this, but note that it gives up type-safety. Moreover, the only way to do this is to allow a call with any type, not just any type that is some structure type, so you have to check that what you got was in fact some struct type:
func structValues(item interface{}) {
if reflect.ValueOf(item).Kind() != reflect.Struct {
... do something here ...
}
Having made that check—or deferring it slightly, or omitting it to allow reflect
to panic instead—you then need to replace reflect.ValueOf(&item).Elem()
with the simpler reflect.ValueOf(item)
.
If you wish to allow pointers to structures as well as actual structures, you can make that happen pretty simply by using reflect.Indirect
first. The result is:
func structValues(item interface{}) []string {
e := reflect.Indirect(reflect.ValueOf(item))
if e.Kind() != reflect.Struct {
panic("not a struct")
}
values := []string{}
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
Leave out the reflect.Indirect
if you want to make sure that callers do their own indirection when they have a pointer.
(Note that the panic
here is not very friendly. If you want proper debugging, consider either just printing the struct directly with %v
or %#v
, or for something much more thorough, the spew package.)
Complete example here on the Go Playground uses your type Item struct
from your own link.
Upvotes: 2