I have a function that iterates through all fields of an interface passed as parameter. In order to achieve this is I am using reflection. The issue is that I do not know how to obtain the address of a non-pointer field. Here is an example:
type Z struct {
Id int
}
type V struct {
Id int
F Z
}
type T struct {
Id int
F V
}
The above code represents my test structures. Now here is the actual function which traverses a specified structure and lists details about it:
func InspectStruct(o interface{}) {
val := reflect.ValueOf(o)
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()
}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
address := "not-addressable"
if valueField.Kind() == reflect.Interface && !valueField.IsNil() {
elm := valueField.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
valueField = elm
}
}
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
address = fmt.Sprint(valueField.Addr().Pointer())
}
fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\t, Field type: %v\t, Field kind: %v\n", typeField.Name,
valueField.Interface(), address, typeField.Type, valueField.Kind())
if valueField.Kind() == reflect.Struct {
InspectStruct(valueField.Interface())
}
}
}
And here is the actual test after structure instantiation/initialization:
t := new(T)
t.Id = 1
t.F = *new(V)
t.F.Id = 2
t.F.F = *new(Z)
t.F.F.Id = 3
InspectStruct(t)
And finally the output of InspectStruct call:
Field Name: Id, Field Value: 1, Address: 408125440 , Field type: int , Field kind: int
Field Name: F, Field Value: {2 {3}}, Address: 408125444 , Field type: main.V , Field kind: struct
Field Name: Id, Field Value: 2, Address: not-addressable , Field type: int , Field kind: int
Field Name: F, Field Value: {3}, Address: not-addressable , Field type: main.Z , Field kind: struct
Field Name: Id, Field Value: 3, Address: not-addressable , Field type: int , Field kind: int
As you can see I am using recursion, so if one of the fields is a struct kind then I call InspectStruct for it. My issue is that though all fields have been initialized for the entire structure "t" hierarchy, I am not able to get the address for any field located at a higher depth than "t". I would really appreciate any help.
Passing reflect.Value
instead of interface{}
seems to fix the problem, however I don't know why valueField.Interface()
doesn't work.
Working example : http://play.golang.org/p/nleA2YWMj8
func InspectStructV(val reflect.Value) {
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()
}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
address := "not-addressable"
if valueField.Kind() == reflect.Interface && !valueField.IsNil() {
elm := valueField.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
valueField = elm
}
}
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
address = fmt.Sprintf("0x%X", valueField.Addr().Pointer())
}
fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\t, Field type: %v\t, Field kind: %v\n", typeField.Name,
valueField.Interface(), address, typeField.Type, valueField.Kind())
if valueField.Kind() == reflect.Struct {
InspectStructV(valueField)
}
}
}
func InspectStruct(v interface{}) {
InspectStructV(reflect.ValueOf(v))
}
The reason Interface()
doesn't work is because of the interface wrapper it returns. To give an idea of what's going on, let's look at what we're doing without reflection:
type MyStruct struct {
F Foo
}
type Foo struct {
i int
}
func ExtractField(ptr *MyStruct) interface{} {
return ptr.F
}
func main() {
ms := &MyStruct{Foo{5}}
f := ExtractField(ms).(Foo) // extract value
f.i = 19
fmt.Println(f, ms.F) // ???
fmt.Println(&f == &ms.F) // Not the same!
}
(Playground)
However, think about the interface{}
this returns. What is it wrapping? The value of ptr.F
-- that is, a copy of it. This is what value.Interface
does, it returns you the interface{}
wrapping the field. There is no longer any pointer metadata, it's completely detached from the original struct.
As you'll note, passing a value directly to reflect.ValueOf
will always return false
for CanAddr for the "top tier" -- because that address is meaningless, since it would give you the address of the copy of the value, changing it wouldn't really mean anything. (Keep in mind that pointers are values too -- if you want the address of a pointer-valued field like *Foo
, you're really looking for **Foo
).
So, in our example above, if we were to naively pass in reflect.ValueOf(ExtractField(ms))
we'd get the ValueOf
f
, which not only doesn't have the address you want -- it isn't even addressable according to reflect because it would never give a valid address as far as reflect is concerned (the only address it could give you is the address of the internal value copy in the Value
struct).
So why does passing the Value
down the rabbit hole work? Well, the only real way to say it is that reflect.Value
maintains the necessary metadata when you use Elem
and Field
, while the interface{}
cannot. So while the reflect.Value
may look like:
// Disclaimer: not the real structure of a reflect.Value
type Value struct {
fieldAddress uintptr
value Foo
}
All it can give you is this
// Again, an abstraction of the real interface wrapper
// just for illustration purposes
type interface{} struct {
value Foo
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With