Extracting Generic Struct Values by Reflection - go

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

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.

Related

Why can not use Pointer() method when reflect.Value is passed to an interface in golang?

I am writing a unit test to check equality of struct that contains func.
Here are my test code.
Go Palyround
When comparing, I used a func named GetFunctionName to get function's name for going.
func GetFunctionName(i interface{}) string {
fmt.Printf("type in GetFunctionName: %v\n", reflect.TypeOf(reflect.ValueOf(i)))
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
Also a compare function was made.
func SelectCompareStruct(got interface{}, want interface{}) {
rvGot := reflect.ValueOf(got)
rtGot := rvGot.Type()
rvWant := reflect.ValueOf(want)
rtWant := rvWant.Type()
for i := 0; i < rtGot.NumField(); i++ {
fieldGot := rtGot.Field(i)
fieldWant := rtWant.Field(i)
valueGot := rvGot.FieldByName(fieldGot.Name)
valueWant := rvWant.FieldByName(fieldWant.Name)
fmt.Printf("type in SelectCompareStruct: %v\n", reflect.TypeOf(reflect.ValueOf(valueGot)))
// Works
gotFuncNameInner := runtime.FuncForPC(valueGot.Pointer()).Name()
wantFuncNameInner := runtime.FuncForPC(valueWant.Pointer()).Name()
fmt.Printf("gotFuncNameInner:\n\t\t\t%v\nwantFuncNameInner:\n\t\t\t%v\n", gotFuncNameInner, wantFuncNameInner)
// Does not work
gotFuncName := GetFunctionName(valueGot)
wantFuncName := GetFunctionName(valueWant)
fmt.Printf("gotFuncName:\n\t%v\n wantFuncName:\n\t%v\n", gotFuncName, wantFuncName)
}
}
You can see, when I write directly to get function's name, it works.
However, it does not work when using a func instead.
Although, both of which type that apply Pointer() method are reflect.Value type.
Yes, I can change input type of GetFunctionName to reflect.Value for working.
That's not good for other use cases. I want to make a function for getting name for versatility.
It will be beautiful to make input type interface{}.
Anyone have any idea why? And how to fix it?
The problem is that you are calling reflect.Value on a reflect.Value. Fix by removing the extra call to reflect.Value.
func GetFunctionName(v reflect.Value) string {
fmt.Printf("type in GetFunctionName: %v\n", v.Type())
return runtime.FuncForPC(v.Pointer()).Name()
}
Run it on the playground.

cast interface{} to []interface{}

How can I cast an interface{} to []interface{} ?
rt := reflect.ValueOf(raw)
switch rt.Kind() {
case reflect.Slice:
src := raw.([]interface{}) //this operation errors out
for _,_ := range src {
//some operation
}
}
I get an error panic: interface conversion: interface {} is []string, not []interface {}
I want make this method generic enough to handle any type, not a fixed type.
I'm very new to Go and I'm stuck with this problem, most likely I'm doing it wrong. Any suggestion how can I get around this ?
Edit:
Some operation is json.Marshal which return byte array.
What I'm really trying to do:
I have a function that receives interface type, if it is an array/slice then I would like to run json.Marshal on each item rather than apply it as a whole. Basically, I'm trying to break up the JSON blob if the first level object is an array, and yes it needs to be generic.
As the error message states, a []string is not an []interface{}. See the FAQ for an explanation.
Use the reflect API do to this generically:
v := reflect.ValueOf(raw)
switch v.Kind() {
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
elem := v.Index(i).Interface()
// elem is an element of the slice
}
}
Run it on the Playground.

How do you pass a slice of *interface{} as arguments?

I want to use Scan() in package sql, but the number of columns, and hence the number of arguments, will change at runtime. This is the signature of Scan():
func (rs *Rows) Scan(dest ...interface{}) error
According to the documentation, *interface{} is one of the types accepted by Scan(). So I want to create a slice of []*interface{} and that expand as arguments.
This is what I thought would work:
func query(database *sql.DB) {
rows, _ := database.Query("select * from testTable")
for rows.Next() {
data := make([]*interface{}, 2)
err := rows.Scan(data...) // Compilation error
fmt.Printf("%v%v\n", *data[0], *data[1])
if err != nil {
fmt.Println(err.Error())
}
}
}
Compilation fails with cannot use data (type []*interface {}) as type []interface {} in argument to rows.Scan. I thought that data... would expand to &data[0], &data[1], but apparently not. I don't understand the error message. *interface{} is compatible with interface{}, so why can't I expand the slice of pointers to interface types?
This works:
func query(database *sql.DB) {
rows, _ := database.Query("select * from testTable")
for rows.Next() {
data := make([]*interface{}, 2)
err := rows.Scan(&data[0], &data[1]) // Only changed this line
fmt.Printf("%v%v\n", *data[0], *data[1]) // Outputs "[48][116 101 120 116]"
if err != nil {
fmt.Println(err.Error())
}
}
}
I can't use this however, because the number of columns is unknown at compile time. How can I write this code so that I can pass a variable number of *interface{} to rows.Scan()?
First, you must not use []*interface{} slice of pointers to interface rather than []interface{} where the interfaces are pointers. []*interface{} is different from []interface{}. Just create a slice of interfaces where each element is a pointer to a concrete type.
Here is a snippet how you would do this.
var x int
var s string
data := []interface{}{&x, &s}
rows.Scan(data...)
Note on the use of the ... spread operator.
Here are some related questions that will explain a bit more:
golang: slice of struct != slice of interface it implements?
Cannot convert []string to []interface {}
If you really want to pass a []*interface{} (perhaps you don't know the concrete types of the output) you must first wrap each *interface{} in a interface{}:
values := make([]interface{}, columnsCount)
for i := range values {
values[i] = new(interface{})
}
Individual values passed into a ...interface{} parameter are automatically wrapped in a interface{}, but just like []int... won't satisfy ...interface{}, neither will []*interface{}....

Get all fields from an interface

How do I know the fields I can access from the reply object/interface? I tried reflection but it seems you have to know the field name first. What if I need to know all the fields available to me?
// Do sends a command to the server and returns the received reply.
Do(commandName string, args ...interface{}) (reply interface{}, err error)
You can use the reflect.TypeOf() function to obtain a reflect.Type type descriptor. From there, you can list fields of the dynamic value stored in the interface.
Example:
type Point struct {
X int
Y int
}
var reply interface{} = Point{1, 2}
t := reflect.TypeOf(reply)
for i := 0; i < t.NumField(); i++ {
fmt.Printf("%+v\n", t.Field(i))
}
Output:
{Name:X PkgPath: Type:int Tag: Offset:0 Index:[0] Anonymous:false}
{Name:Y PkgPath: Type:int Tag: Offset:4 Index:[1] Anonymous:false}
The result of a Type.Field() call is a reflect.StructField value which is a struct, containing the name of the field among other things:
type StructField struct {
// Name is the field name.
Name string
// ...
}
If you also want the values of the fields, you may use reflect.ValueOf() to obtain a reflect.Value(), and then you may use Value.Field() or Value.FieldByName():
v := reflect.ValueOf(reply)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
Output:
1
2
Try it on the Go Playground.
Note: often a pointer to struct is wrapped in an interface. In such cases you may use Type.Elem() and Value.Elem() to "navigate" to the pointed type or value:
t := reflect.TypeOf(reply).Elem()
v := reflect.ValueOf(reply).Elem()
If you don't know whether it's a pointer or not, you can check it with Type.Kind() and Value.Kind(), comparing the result with reflect.Ptr:
t := reflect.TypeOf(reply)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
// ...
v := reflect.ValueOf(reply)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
Try this variant on the Go Playground.
For a detailed introduction to Go's reflection, read the blog post: The Laws of Reflection.

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

Resources