问题描述
我有一个函数遍历作为参数传递的接口的所有字段。为了实现这一点,我正在使用反射。问题是我不知道如何获取非指针字段的地址。这里是一个例子:
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))
}
这篇关于使用反射获取指向值的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!