本文介绍了使用反射获取指向值的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数遍历作为参数传递的接口的所有字段。为了实现这一点,我正在使用反射。问题是我不知道如何获取非指针字段的地址。这里是一个例子:

  type Z struct {
Id int
}

type V struct {
Id int
FZ
}

type T struct {
Id int
FV
}

上面的代码代表了我的测试结构。现在这里是遍历指定结构并列出其详细信息的实际函数:

$ p $ func InspectStruct(o interface {}){
val:= reflect.ValueOf(o)
如果val.Kind()== reflect.Interface&& !val.IsNil(){
elm:= val.Elem()
if elm.Kind()== reflect.Ptr&& !elm.IsNil()&& el.Elem()。Kind()== reflect.Ptr {
val = elm
}
}
如果val.Kind()== reflect.Ptr {
val = val.Elem()
}

for i:= 0;我< 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(字段名称:%s,\ t字段值:%v,\ t地址:%v \ t,字段类型:%v \ t,字段类型:%v\\\
,typeField.Name,
valueField.Interface(),address,typeField.Type,valueField.Kind())

if valueField.Kind()== reflect.Struct {
InspectStruct(valueField.Interface())
}
}
}

这里是结构实例化/初始化后的实际测试:

  t:= new (T)
t.Id = 1
tF = * new(V)
tFId = 2
tFF = * new(Z)
tFFId = 3

InspectStruct(t)

最后输出InspectStruct调用:

 字段名称:Id,字段值:1,地址:408125440,字段类型:int,字段类型:int 
字段名称:F,字段值:{2 {3字段类型:int,字段类型:int
字段名称:F,字段值:{3},地址:not-addressable,字段类型:main.Z,字段类型:struct
字段名称:Id,字段值:3,地址:not-addressable,字段类型:int,字段类型:int

正如您所看到的,我正在使用递归,的字段是一个结构类型,然后我为它调用InspectStruct。
我的问题是,虽然所有字段都已经初始化为整个结构t层次结构,但我无法获得位于比t更高深度的任何字段的地址。我真的很感激任何帮助。

解决方案

传递 reflect.Value 代替 interface {} 似乎解决了这个问题,但是我不知道为什么 valueField.Interface()不起作用。



工作示例:

  func InspectStructV(val reflect.Value){
if val.Kind()== reflect.Interface&& !val.IsNil(){
elm:= val.Elem()
if elm.Kind()== reflect.Ptr&& !elm.IsNil()&& el.Elem()。Kind()== reflect.Ptr {
val = elm
}
}
如果val.Kind()== reflect.Ptr {
val = val.Elem()
}

for i:= 0;我< 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()&&如果valueField.Kind()==反映,elm.Elem()。Kind()== reflect.Ptr {
valueField = elm
}
}

。 Ptr {
valueField = valueField.Elem()

$ b if valueField.CanAddr(){
address = fmt.Sprintf(0x%X,valueField .Addr().Pointer())
}

fmt.Printf(字段名称:%s,\ t字段值:%v,\ t地址:%v \\ \\ t,字段类型:%v \ t,字段种类:%v\\\
,typeField.Name,
valueField.Interface(),地址,typeField.Type,valueField.Kind())

if valueField.Kind()== reflect.Struct {
InspectStructV(valueField)
}
}
}

func InspectStruct(v interface {}){
InspectStructV(reflect.ValueOf(v))
}


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))
}

这篇关于使用反射获取指向值的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 21:58