Necessity of calling Elem() method on pointer-receiver for struct reflection - pointers

I have struct
type ChartOpts struct {
Name mypakage.MyType
Repo mypakage.MyType
}
on which I want to set a receiver for reflection.
func (chartOpts *ChartOpts) BindFlags() {
fields := reflect.TypeOf(chartOpts)
values := reflect.ValueOf(chartOpts)
num := fields.NumField()
fmt.Println(fields, values, num)
}
The above code panics
panic: reflect: NumField of non-struct type *app.ChartOpts
Why do I need to call the Elem() method to fix this?
func (chartOpts *ChartOpts) BindFlags() {
fields := reflect.TypeOf(chartOpts)
values := reflect.ValueOf(chartOpts)
num := fields.Elem().NumField()
fmt.Println(fields, values, num)
}

Because type of chartOpts is *ChartOpts, a pointer to ChartOpts type. Pointers have no fields, only structs. Calling Elem() on its type descriptor will return a type descriptor that represents / describes ChartOpts, a struct type which does have fields.

Related

reflect.Pointer() returned value is not the value address

type BookInfo struct {
Meta *TableMeta
...
}
func (si *schemaInfo) getTabInfo(obj interface{}) (*tabInfo, error) {
typ := reflect.TypeOf(obj)
val := reflect.ValueOf(obj)
if typ.Kind() != reflect.Ptr {
return nil, errors.New("nborm.schemaInfo.getDBInfo() error: required a pointer")
}
meta := *(**TableMeta)(unsafe.Pointer(val.Pointer()))
...
}
getTabInfo() works well, but I want to know why val.Pointer() return a value of **TableMeta? Why not a *TableMeta?The document of reflect says,
Pointer returns v's value as a uintptr. It returns uintptr instead of
unsafe.Pointer so that code using reflect cannot obtain
unsafe.Pointers without importing the unsafe package explicitly. It
panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or
UnsafePointer.
In my mind:
info := &BookInfo{}
val := reflect.ValueOf(info)
ptr := val.Pointer()
meta := (*TableMeta)(unsafe.Pointer(val.Pointer()))
should work, but infact when I called val.Pointer(), the returned value is the pointer of *TableMeta(**TableMeta).
The value you have is a pointer to a BookInfo struct, it is of type *BookInfo. And the type of BookInfo.Meta field is also a pointer, it is of type *TableMeta, thus a *BookInfo can then be looked at as **TableMeta, hence the "double" pointer.
It's true that the struct pointer points to its first field, but don't build on it. It's fragile. If you add a field before it, it'll break badly (which will only happen at runtime, no compile time messages due to package unsafe).
So if the value is of type *BookInfo, simply obtain that out of the reflect.Value wrapper, then you can refer to its field like value.Meta, which will be of type *TableMeta. Avoid using package unsafe, especially if it's not needed.

Set an interface to nil in Golang

I'm trying to set an internal value of an interface to nil something like the following :
typ := &TYP{InternalState: "filled"}
setNil(typ)
fmt.Printf("Expecting that %v to be nil", typ)
And I need to know how to implement the setNil(typ interface{}) method.
For more details see this code in play.golang.org.
The thing is you don't have an interface value. You have a pointer value, a pointer to a concrete type. That is not the same as an interface value.
If you want to change the value of a variable of any type, you have to pass a pointer to it. This also includes variables of interface type, and also variables of pointer type. This is one of those very rare cases when a pointer to interface{} makes sense (*interface{}), in fact it's inevitable.
But if your function expects an interface and you pass a non-interface value, an interface value will be created implicitly and you could only nil this implicitly created value.
So we have 2 different / distinct cases:
Function to nil an interface{}
func setNilIf(v *interface{}) {
*v = nil
}
Using it:
var i interface{} = "Bob"
fmt.Printf("Before: %v\n", i)
setNilIf(&i)
fmt.Printf("After: %v\n", i)
Output:
Before: Bob
After: <nil>
So it works.
Function to nil a pointer; using unsafe
Actually this is your case. We want to change the value of a variable of pointer type. To accept a pointer to any type, we can use unsafe.Pointer. unsafe.Pointer is a language support, it's a special pointer type which can be converted from and to any pointer type.
We want to accept the address (pointer) of the pointer variable, which is something like **SomeType. To actually be able to assign a new value (nil) to the pointer variable, we have to dereference it (* operator). But unsafe.Pointer cannot be dereferenced, so first we have to convert it to a pointer to pointer to "something", but since we only want to assign nil (which is the same to all pointer types regardless of the type of the pointed value), the "something" doesn't matter, I will just use int, and so I will convert the unsafe.Pointer pointer value to **int.
func setNilPtr(p unsafe.Pointer) {
*(**int)(p) = nil
}
Using it:
typ := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ)
setNilPtr(unsafe.Pointer(&typ))
fmt.Printf("After: %v\n", typ)
Output:
Before: &{filled}
After: <nil>
So this one also works. There is still another way using reflection:
Function to nil a pointer; using reflect
You can also nil a pointer using reflection only (reflect package). We still have to pass the address of the variable of pointer type. Note that in this case the type of the parameter will simply be interface{}. And it will contain a dynamic type like **SomeType. Since pointers have zero value nil, we can obtain such a value with reflect.Zero() which we will set using Value.Set():
func setNilPtr2(i interface{}) {
v := reflect.ValueOf(i)
v.Elem().Set(reflect.Zero(v.Elem().Type()))
}
Using it:
typ2 := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ2)
setNilPtr2(&typ2)
fmt.Printf("After: %v\n", typ2)
Output:
Before: &{filled}
After: <nil>
So this one also works. Try these on the Go Playground.
But seriously: if you want to nil something, assign nil to it. Do not complicate things unnecessarily.
i = nil
typ = nil

Can't use range on slice made with reflect then passed json.Unmarshal

I am getting the following errors from the code below:
invalid indirect of typedSlice (type interface {})
cannot range over typedSlice (type interface {})
This is confusing to me because reflect.TypeOf(copy) matches the type of t.
func Unmarshal(t reflect.Type) []interface{} {
ret := []interface{}{}
s := `[{"Name":"The quick..."}]`
slice := reflect.Zero(reflect.SliceOf(t))
o := reflect.New(slice.Type())
o.Elem().Set(slice)
typedSlice := o.Interface()
json.Unmarshal([]byte(s), typedSlice)
fmt.Println(typedSlice) // &[{The quick...}]
fmt.Println(reflect.TypeOf(typedSlice)) //same type as t
fmt.Println(*typedSlice) // invalid indirect of copy (type interface {})
for _, l := range typedSlice { //cannot range over copy (type interface {})
ret = append(ret, &l)
}
return ret
}
I've created a go playground with working code to help.
Why does it appear that this slice prints one type but compiles as another?
invalid indirect of typedSlice (type interface {})
You can't dereference typedSlice, because it's an interface{}. You would have to extract the pointer with a type assertion
realSlice := *typedSlice.(*[]Demo)
cannot range over typedSlice (type interface {})
Again, since typedSlice is an interface{}, you can't range over it. If you want to range over the values you need to use a type assertion, or iterate manually via reflect:
for i := 0; i < o.Elem().Len(); i++ {
ret = append(ret, o.Elem().Index(i).Interface())
}

Obtaining reflect.Ptr type to field in a Go struct

I am trying to pass to a third-party package a variadic list of pointers to fields in a struct. The package accepts a variadic interface{} list ( func Persist(...interface) error ), where each of the interface values is a pointer to a variable. I created a function that mocks how the third-party library and prints out the Type and Kind of the pointers (called mockFunction below).
When I pass it the address of the struct variables in a non-variadic way, they have their primitive Types and Values within the mocked function using the reflect calls. However, when I pass them in a variadic way using expansion, they have Type: Type: reflect.Value and Kind: struct. The third-party package does not know how to handle them in this form.
I would like to figure out a way to call the third-party package with a slice of interface{} (e.g. inv := make([]interface{}, 3) and use variadic expansion on the call Persist(inv...) if at all possible.
Here is the code with a link to Go Playground below:
package main
import (
"fmt"
"reflect"
)
type Investment struct {
Price float64
Symbol string
Rating int64
}
func main() {
inv := Investment{Price: 534.432, Symbol: "GBG", Rating: 4}
s := reflect.ValueOf(&inv).Elem()
variableParms := make([]interface{}, s.NumField())
for i := 0; i < s.NumField(); i++ {
variableParms[i] = s.Field(i).Addr()
}
// non-variadic call
mockFunction(&inv.Price, &inv.Symbol, &inv.Rating)
//variadic call
mockFunction(variableParms...)
}
func mockFunction(values ...interface{}) {
for i, value := range values {
rv := reflect.ValueOf(value)
fmt.Printf("value %d has Type: %s and Kind %s\n", i, rv.Type(), rv.Kind())
}
}
Go Playground Link
When I run it with the non-variadic parameters, the call to mockFunction returns the native Types and Kinds and the third-party package processes them fine:
value 0 has Type: *float64 and Kind ptr
value 1 has Type: *string and Kind ptr
value 2 has Type: *int64 and Kind ptr
When I run it with the variadic parameters, the values are different and the third-party package does not know how to handle these types:
value 0 has Type: reflect.Value and Kind struct
value 1 has Type: reflect.Value and Kind struct
value 2 has Type: reflect.Value and Kind struct
Is there any way to structure the slice definition and the call to what is placed in to the slice so that it can be variadic expanded and look like passing the pointers to the struct fields in the non-variadic way?
Addr() returns the reflect Value for the field pointer. Call Ptr() on the value to get the actual pointer as an interface{}.
variableParms[i] = s.Field(i).Addr().Ptr()
playground
I think that perhaps Go's handling for this case has changed since 2014 - certainly the code above no longer works for me with Go 1.10...
However the following code works for me to create an appropriate []interface{} to use in the described way...
func settableSliceFromStruct(inStruct interface{}) ([]interface{}, error) {
t := reflect.TypeOf(inStruct)
if t.Kind() != reflect.Ptr {
return nil, errors.New("can only assign values with pointer to struct")
}
v := reflect.ValueOf(inStruct).Elem()
t = t.Elem()
dataColumns := make([]interface{}, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
if weWantToIncludeThis(t.Field(i)) {
dataColumns = append(dataColumns, v.Field(i).Addr().Interface())
}
}
return dataColumns, nil
}
The critical part here would be for your code to use:
variableParms[i] = s.Field(i).Addr().Interface()

Reflect thinks struct Value is also a ptr?

I have a data structure like this demo. As you can see, foo has an embedded pointer to bar:
type foo struct {
*bar
}
type bar struct {
S []byte
}
And I'm using the reflect package like this:
func test(x interface{}) {
var v = reflect.ValueOf(x)
if v.Kind() == reflect.Struct {
fmt.Println("was a struct")
// panic: reflect: call of reflect.Value.Elem on struct Value
// v = v.Elem()
// panic: reflect: call of reflect.Value.Field on ptr Value
v = v.FieldByName("S")
}
}
func main() {
var f foo
test(f)
fmt.Println(string(f.S))
}
So v.Kind() is recognized as a reflect.Struct, but if I try to treat it like a struct by using .FieldByName("S"), it panics because it thinks v is a ptr.
So then if I try to treat it like a ptr by calling .Elem(), it panics because it thinks v is a struct.
I've tried reflect.Indirect(), as well as a few other things, but I can't figure out how to get the field of an embedded pointer.
Is there a way to get the reflect.Value representation from an embedded pointer to a struct?
Demo: http://play.golang.org/p/n0eea6XW3I
EDIT: Also tried v = v.FieldByName("bar"), but got:
panic: runtime error: invalid memory address or nil pointer dereference
The first thing we need to realize is that the line var f foo is equivalent to f := foo{}. This initializes the internal field bar (of type *bar) to its zero value... nil. The behavior of embedded types and reflect seems to be that it treats the embedded type's fields as fields of the type itself. So when you request v.FieldByName("S") it's trying to find that field in f's member, bar, which is nil.
You're trying to do this (*f.bar).S. (In Go the explicit pointer dereference isn't needed, but it makes my point). Now the question is: if you change is to v.FieldByName("bar") why does it give an error? Same reason.
Look closely at the stack trace, the FieldByName line no longer crashes, the line that crashes is fmt.Println(string(f.S)). Again, semantically you're doing (*f.bar).S. But the member "bar" is nil, so you are, in fact, doing a nil pointer dereference.
You can fix both errors by changing var f foo to f := foo{&bar{}}.
i was getting this error " panic: reflect: call of reflect.Value.Elem on struct Value" bcz of this line "reflect.ValueOf(parameterName).Elem()"
1.When i am using Elem() in reflex ,it means parameterName inside valueOf() should be a pointer to structure
func Search(flight interface{}, key string) string {
val := reflect.ValueOf(flight).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
if key == strings.ToLower(typeField.Name) {
return valueField.Interface().(string)
}
}
return ""
}
Now while calling search function my call should be like this!
result := Search(&flights, key)

Resources