Given
// I know that behind SomeInterface can hide either int or a pointer to struct
// In the real code I only have v, not i
i := something.(SomeInterface)
v := reflect.ValueOf(i)
var p uintptr
if "i is a pointer to struct" {
p = ???
}
I need some way to distinguish between pointers and values in this situation.
If i was a pointer to struct, I need to cast it to uintptr.
Something I discovered so far: the second member of the (*reflect.Value).InterfaceData() will be the pointer to the struct, in case it is a struct. I have no idea what it is in case it is not a struct.
Use the Pointer method to get the address of a struct as a uintpr:
var p uintptr
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
p = v.Pointer()
}
playground example
This code assumes that v is the result of calling reflect.ValueOf(i) as shown in the question. In this scenario, v represents i's element, not i. For example, if interface i contains an int, then v.Kind() is reflect.Int, not reflect.Interface.
If v has an interface value, then drill down through the interface to get the uintptr:
if v.Kind() == reflect.Interface {
v = v.Elem()
}
var p uintptr
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
p = v.Pointer()
}
playground example
Related
Given this struct
type A struct {
b *B
c string
d string
}
I want to check with reflect which fields have a struct behind the pointer type, so specifically I want to create a condition that would only be true when iterating over field b. From what I've tried using the reflect documentation I always end up with an invalid Value kind which doesn't allow me to go further as every subsequent method panics.
package main
import (
"fmt"
"reflect"
)
type A struct {
b *B
c string
d string
}
type B struct {
}
func main() {
val := reflect.ValueOf(A{})
for i := 0; i < val.Type().NumField(); i++ {
if val.Field(i).Kind() == reflect.Ptr {
fmt.Println(reflect.Indirect(val.Field(i)).Kind())
}
fmt.Println(val.Field(i).Kind())
}
}
https://play.golang.org/p/oRry3ZubRxI
You get invalid value, because the val.b pointer field is nil, and you can't dereference a nil pointer. If you want your code to work, you have to initialize it with a valid pointer:
val := reflect.ValueOf(A{b: &B{}})
With this change it works and outputs (try it on the Go Playground):
struct
ptr
string
If you want it to work without having to initialize the pointer, then you have to work on the types and not values:
val := reflect.ValueOf(A{})
t := val.Type()
for i := 0; i < t.NumField(); i++ {
if ft := t.Field(i).Type; ft.Kind() == reflect.Ptr {
fmt.Println(ft.Elem().Kind())
}
fmt.Println(t.Field(i).Type.Kind())
}
This outputs the same, try this one on the Go Playground.
I just can't find the way to get a slice of pointer to each attribute of a given struct. I am using reflection to get my pointers (Thanks to https://stackoverflow.com/a/24348352/6093604)
if valueField.CanAddr() {
address = fmt.Sprintf("0x%X", valueField.Addr().Pointer())
}
As you can see, valueField.Addr().Pointer() returns a pointer addr value, however, using reflection, I would like to get a usable pointer for sql.Rows.Scan()
So what did I do is:
func StructAttributesToPointersSlice(object interface{}) []interface{} {
val := reflect.ValueOf(object)
if val.Kind() == reflect.Interface && !val.IsNil() {
elm := val.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
val = elm
}
}
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
var ptrs []interface{}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
ptrs = append(ptrs, valueField.Addr().Pointer())
}
}
return ptrs
}
But when I try to use it for Scan() sql function:
var values []interface{}
// Iterate over each rows got from the query
for rows.Next() {
ptrs := utils.StructAttributesToPointersSlice(&newObject)
for _, item := range ptrs {
fmt.Println(reflect.TypeOf(item))
}
err = rows.Scan(ptrs...)
if err != nil {
return nil, model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
} else {
values = append(values, newObject)
}
}
I am getting this error:
sql: Scan error on column index 0: destination not a pointer
I know it's because it's not the good type since it's a uintptr, but then how to transform it into usable pointer?
Thanks
Use unsafe.Pointer to convert a uintptr to a pointer of some type. As an example, the following expression converts uintptr u to a T pointer:
(*T)(unsafe.Pointer(u))
This conversion does not help in StructAttributesToPointersSlice because the struct fields can be of any type. Also, the conversion from uintptr is not needed and unsafe.
The expression valueField.Addr() is the reflect.Value for the pointer to the field. Call Interface() to get the actual pointer. To fix the program, change
ptrs = append(ptrs, valueField.Addr().Pointer())
to
ptrs = append(ptrs, valueField.Addr().Interface())
Here's a simplified version of the function:
func StructAttributesToPointersSlice(object interface{}) []interface{} {
v := reflect.ValueOf(object)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
panic("argument must be a pointer to struct")
}
v = v.Elem()
var result []interface{}
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if !f.CanSet() {
continue
}
result = append(result, f.Addr().Interface())
}
return result
}
Some notes about this code:
The argument must be a pointer to a struct.
There's no need to call CanAddr on the fields. The check for pointer to struct covers this.
The CanSet() skips over unexported fields. You may want it to panic instead.
The function panics for errors in the caller. Consider returning an error instead.
playground example
I noticed, quite by accident, that I can successfully pass both a pointer to a struct, and a pointer to a pointer to a struct to json.Unmarshal(), and both work just fine:
package main
import (
"testing"
"encoding/json"
)
type Person struct {
Name string
Age int
}
func TestMarshaling(t *testing.T) {
foo := &Person{Name: "bob", Age: 23}
// marshal it to bytes
b, err := json.Marshal(foo)
if err != nil {
t.Error(err)
}
bar := &Person{} // pointer to new, empty struct
err = json.Unmarshal(b, bar) // unmarshal to bar, which is a *Person
if err != nil {
t.Error(err)
}
testBob(t, bar) // ok
bar = &Person{} // pointer to new, empty struct
err = json.Unmarshal(b, &bar) // wait a minute, passing in a **Person, yet it still works?
if err != nil {
t.Error(err)
}
testBob(t, bar) // ok
}
func testBob(t *testing.T, person *Person) {
if person.Name != "bob" || person.Age != 23 {
t.Error("not equal")
}
}
I was really surprised that the second one (unmarshal to **Person) worked.
What's going on in json.Unmarshal()? Is it dereferencing the pointers until it finds a struct?
The documentation offers:
To unmarshal JSON into a pointer, Unmarshal first handles the case of
the JSON being the JSON literal null. In that case, Unmarshal sets
the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into the
value pointed at by the pointer
It seems to be doing a bit more than that. What's really going on?
Fleshing out my question more: how does it know to automatically dereference my pointer to a pointer? The documentation says it will unmarshal "into the value pointed at by the pointer". Since the value of my pointer is in fact another pointer, and has no Name/Age fields, I expected it to stop there.
To be clear: I'm not saying there's a bug or misfeature in Unmarshal(); I'm trying to satisfy my astonishment that it works at all when given a ptr-to-ptr, and avoid any potential pitfalls in my use of it.
The json package has no reason to "stop at a pointer", since a pointer means nothing in json. It has to keep walking the tree in order to find a value to write. Since the json package is going to allow unmarshaling the same value into Type or *Type, it stands to reason that it should be able to unmarshal that into **Type, which is also a valid type in Go.
For a example, if Person were defined using pointers to differentiate between nil and zero values, and you were unmarshaling into a slice of []*Person, the json package needs to follow those pointers, and allocate values if necessary. The same applies if a field in Person were defined as a **string.
type Person struct {
Name **string
Age *int
}
type People []*Person
http://play.golang.org/p/vLq0nJPG5M
The json.Unmarshal implementation takes multiple indirection into account. Check the source here, in particular the decodeState.indirect method:
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
//and so on
}
return nil, nil, v
The same method is called when unmarshaling arrays:
func (d *decodeState) array(v reflect.Value) {
u, ut, pv := d.indirect(v, false)
//...
That would have me believe that go can handle double indirection just fine. If nothing else, the json package source is a great example of what the reflect package is all about.
In short, values are checked, if the decoder is dealing with pointers, it will use reflection to work out how many levels of indirection there are, and determine what type the target has/is. The place to start from in the decode source is this: func (d *decodeState) unmarshal(v interface{}) (err error) {, from that point on, it's pretty self-explanatory.
As other answers have said, pointers are followed.
A little weird that this errors (nil pointer), but makes sense when you think about it.
package main
import (
"encoding/json"
"fmt"
"log"
)
type MyStruct struct {
A string `json:"a"`
}
func main() {
data := []byte(`{"a":"foo"}`)
var a *MyStruct
err := json.Unmarshal(data, a) // nil ptr
if err != nil {
log.Fatal(err)
}
fmt.Println(a)
}
But this doesn't error (pointer to nil pointer).
package main
import (
"encoding/json"
"fmt"
"log"
)
type MyStruct struct {
A string `json:"a"`
}
func main() {
data := []byte(`{"a":"foo"}`)
var a *MyStruct
err := json.Unmarshal(data, &a) // **MyStruct, ptr to nil ptr
if err != nil {
log.Fatal(err)
}
fmt.Println(a)
}
https://play.golang.org/p/eI8jqWZOmGW
I want to have a generic way which will always return the struct value no matter if it is provided as pointer, slice or array.
My approach towards this looks:
func main() {
p := Person{}
if value(p).Kind() != reflect.Struct {
fmt.Printf("Error 1")
}
if value(&p).Kind() != reflect.Struct {
fmt.Printf("Error 2")
}
if value([]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 3")
}
if value(&[]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 4")
}
}
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
fallthrough
case reflect.Slice, reflect.Array:
v = v.Elem()
}
return v
}
Go Playground
As you can see the problem lays with in getting the struct out of a slice or array.
How do I need to extend the above function to get the struct value from with in an array or slice?
Update: What I want to do is turn []People into People.
If you just want the type even if the slice is nil, you can use something like this:
func value(m interface{}) reflect.Type {
t := reflect.Indirect(reflect.ValueOf(m)).Type()
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
t = t.Elem()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
return t
}
About Type.Elem(), from http://golang.org/pkg/reflect/#Type:
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
//edit updated the function to work on a slice of pointers as well.
I assume that what you mean by "get out of the slice or array" is that you want the first element (that is, the element at index 0)? If that's what you want, then you should use the reflect.Value.Index() method. For example:
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
v = v.Index(0)
}
case reflect.Slice, reflect.Array:
v = v.Index(0)
default:
break LOOP
}
return v
}
Go playground
Note that I also slightly modified the flow logic. You were falling through to the slice/array case from the pointer case. You probably intended for the case condition to be tested again (so it'd effectively say, "if this was a pointer, now check if the thing it pointed to was a slice or an array"), but that's not how fallthrough works. Now it checks the case explicitly.
I have the following query builder function:
func CreateQuery(t interface{}, where string) {
var b bytes.Buffer
b.WriteString("SELECT ")
s := reflect.ValueOf(t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField() - 1; i++ {
b.WriteString(fmt.Sprintf("%s, ", typeOfT.Field(i).Name))
}
//Last one has no Comma
b.WriteString(fmt.Sprintf("%s ", typeOfT.Field(s.NumField() - 1).Name))
b.WriteString(fmt.Sprintf("FROM %s ", typeOfT.Name()))
b.WriteString(where)
fmt.Println(b.String())
}
There works fine when called as follows:
var dst FooStruct
CreateQuery(&dst, "")
But the following raises a "call of reflect.Value.NumField on slice Value" Panic:
var dst []FooStruct
CreateQuery(&dst, "")
How I can I make the function print the fields of a slice's underlying struct type? It seems like I want the inverse of reflect's SliceOf function.
You can only call NumField or Field methods on a reflect.Type representing a struct (i.e. t.Kind() == reflect.Struct).
If you have a slice type, you can access the contained type via the Elem method, which returns another reflect.Type. If the slice contains a struct, then you can call NumField/Field on this type.
You can iterate over the slice, calling CreateQuery for every query:
func CreateQueries(t interface{}, where string) {
v := reflect.ValueOf(t)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
for i := 0; i < v.Len(); i++ {
CreateQuery(v.Index(i).Interface(), where)
}
}
}
Using reflect.Value.Index you can access each field separately, calling .Interface() on the
value yields the interface{} type representation of that value, making it suitable to put
it in your CreateQuery function (which expects a interface{} value).