在Go

时间:2019-11-09 11:12:47

标签: go reflection

给出一个具有字段的结构,我想以符号形式查找特定字段的标记值(不提供字段名称作为字符串)。

type MyStruct struct {
    Foo string `tag:"val"`
}
entity := MyStruct{}
tagVal := getTag(&entity.Foo) // the function would return "val" for Foo field

我想实现一个getTag函数,该函数将为给定字段返回标签值。

1 个答案:

答案 0 :(得分:0)

指向字段值的指针不包含有关所有者结构的任何信息,这是一种间接的方式,因此仅使用指针字段值不足以解决问题。

一种解决方案是将指向所有者结构的指针与指向该结构中字段的指针一起使用,通过反射迭代该结构值的字段,直到迭代字段的地址与给定的字段值指针匹配为止。

https://play.golang.org/p/kaPQ9HF9wAK

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type MyStruct struct {
        Foo string `tag:"val"`
    }
    entity := MyStruct{}
    tagVal := getTag(&entity, &entity.Foo)
    fmt.Println(tagVal) // val
}

func getTag(structPtr, fieldPtr interface{}) string {
    sf, ok := structFieldByValPtr(structPtr, fieldPtr)
    if !ok {
        return ""
    }
    return sf.Tag.Get("tag")
}

func structFieldByValPtr(structPtr, fieldPtr interface{}) (reflect.StructField, bool) {
    v := reflect.Indirect(reflect.ValueOf(structPtr))
    t := v.Type()

    for i := 0; i < v.NumField(); i++ {
        fv := v.Field(i)
        ft := t.Field(i)

        if fv.Addr().Interface() == fieldPtr {
            return ft, true
        }

        if ft.Anonymous {
            sf, ok := structFieldByValPtr(fv.Addr().Interface(), fieldPtr)
            if ok {
                return sf, true
            }
        }
    }

    return reflect.StructField{}, false
}