使用反射从深度嵌套的结构中提取标签

时间:2019-11-24 04:36:56

标签: go struct reflection tags

我正在尝试从一些深层嵌套的结构中提取一些标签。这些结构是从protobuf消息生成的,并包含json标签。

我有一个指向结构的指针,该结构可能包含一个结构,该结构包含我想要其标签的字段。我可以使用类型进行迭代以获取结构的字段,但是当我遇到一个指针字段时,如何获取其值然后递归?

// Struct has hierarchy like this 
a := &somepb.UpdateRequest{
        Updates: []*somepb.UpdateRequest_Foo{
            &somepb.UpdateRequest_Foo{
                Id: 1,
                Foo: &somepb.FooInfo{
                    Metadata: &somepb.Metadata{
                        Name:        "Foo",
                        Description: "Bar",
                    },
                    Some:    "s",
                    Things:  "o",
                    Are:     "m",
                    Broken:  "e",
                    Here:    "p",
                },
            },
        },
 } 

// ParseStruct parses struct tags of given object
func ParseStruct(obj interface{}, tag string) {
    r := reflect.ValueOf(obj)
    if r.Kind() == reflect.Ptr {
        obj = r.Elem().Interface()
    }
    rv := reflect.TypeOf(obj)
    for i := 0; i < rv.NumField(); i++ {
        f := rv.Field(i)
        // This is to avoid getting tags for Metadata itself (from the struct above)
        // which is *Metadata, I want the tags for Name and Description
        // inside *Metadata instead
        if f.Type.Kind() == reflect.Ptr {
            value := f.Tag.Get(tag)
            if len(value) == 0 {
                continue
            }
            fmt.Println(value)
        }
    }
} 

2 个答案:

答案 0 :(得分:1)

reflect.Typereflect.Value都具有Elem()方法。根据{{​​3}},

Elem的{​​{1}}方法。

Type

// Elem returns a type's element type. // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice. Elem() Type

Value.Elem

您可以使用func (v Value) Elem() Value Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is not Interface or Ptr. It returns the zero Value if v is nil. 方法来获取指针的内容,然后使用该内容进行递归。但是,假设您的原始API是Elem(),则需要使用func(interface{},string)来获得有意义的Value.Elem().Interface()。但是,相反,我建议您将API更改为接受interface{}-因为这对于标记提取最为明显。

示例代码:

reflect.Type

请注意,这段代码非常简单-它不会处理切片或地图中的结构标签。

答案 1 :(得分:0)

  

当我遇到一个指针字段时,如何获取其值并   然后递归?

reflect.Valuereflect.Type上遇到指针时,您必须以Elem()继续前进。

reflect.ValueOf(new(string)).Elem()从值*stringstring

reflect.TypeOf(new(string)).Elem()从类型*stringstring