Jay Taylor's notes

back to listing index

Golang - Get pointer to value using reflection

[web search]
Original source (stackoverflow.com)
Tags: golang go pointer stackoverflow.com
Clipped on: 2016-01-12

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.

Image (Asset 2/5) alt=go
asked Jun 22 '14 at 4:39
Image (Asset 3/5) alt=
Mihai H
1,1011920
up vote 6 down vote accepted

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))
}
answered Jun 22 '14 at 5:15
Image (Asset 4/5) alt=
OneOfOne
31.5k43570

I was going to leave this as a comment on OneOfOne's post, but it turned out a little too complex for a comment and very relevant to answering the question and why OneOfOne's answer works correctly.

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
}
answered Jun 22 '14 at 21:46
Image (Asset 5/5) alt=
Jsor
5,4531432
   upvote
  flag
I learned from this, thanks for the detailed answer. – OneOfOne Jun 22 '14 at 23:59
1 upvote
  flag
Thanks for complementing @OneOfOne answer. Much appreciated! – Mihai H Jun 23 '14 at 7:00

Your Answer

asked

1 year ago

viewed

2429 times

active

1 year ago

Blog

Get the weekly newsletter!

  • Top questions and answers
  • Important announcements
  • Unanswered questions

Hot Network Questions

Technology Life / Arts Culture / Recreation Science Other
  1. Stack Overflow
  2. Server Fault
  3. Super User
  4. Web Applications
  5. Ask Ubuntu
  6. Webmasters
  7. Game Development
  8. TeX - LaTeX
  1. Programmers
  2. Unix & Linux
  3. Ask Different (Apple)
  4. WordPress Development
  5. Geographic Information Systems
  6. Electrical Engineering
  7. Android Enthusiasts
  8. Information Security
  1. Database Administrators
  2. Drupal Answers
  3. SharePoint
  4. User Experience
  5. Mathematica
  6. Salesforce
  7. ExpressionEngine® Answers
  8. more (13)
  1. Photography
  2. Science Fiction & Fantasy
  3. Graphic Design
  4. Movies & TV
  5. Seasoned Advice (cooking)
  6. Home Improvement
  7. Personal Finance & Money
  8. Academia
  9. more (9)
  1. English Language & Usage
  2. Skeptics
  3. Mi Yodeya (Judaism)
  4. Travel
  5. Christianity
  6. Arqade (gaming)
  7. Bicycles
  8. Role-playing Games
  9. more (21)
  1. Mathematics
  2. Cross Validated (stats)
  3. Theoretical Computer Science
  4. Physics
  5. MathOverflow
  6. Chemistry
  7. Biology
  8. more (5)
  1. Stack Apps
  2. Meta Stack Exchange
  3. Area 51
  4. Stack Overflow Careers
site design / logo © 2016 Stack Exchange Inc; user contributions licensed under cc by-sa 3.0 with attribution required
rev 2016.1.6.3151