使用JSON标签获取Golang结构体字段名

11

我有一个结构体:

type Human struct {
    Head  string  `json:"a1"`
    Body  string  `json:"a2"`
    Leg   string  `json:"a3"`
}
我可以通过提供JSON标签名称来获取结构体字段名吗?大概像这样:
fmt.Println(getFieldName("a1")) // "Head"
fmt.Println(getFieldName("a2")) // "Body"
fmt.Println(getFieldName("a99")) // ""

func getFieldName(tag string) (fieldname string) {
    /* ... */
}

我应该如何实现getFieldName函数?我在网上看到需要使用reflect包,不知道有没有帮助的手?:)


2
https://golang.org/pkg/reflect/#example_StructTag - zerkms
4
这是一个Go语言程序,它可以将一个字符串反转并输出。程序首先定义了一个名为s的字符串变量,并将其赋值为"hello, world"。然后,它使用一个for循环将字符串s中的字符逆序追加到一个名为result的空字符串变量中。最后,程序输出了反转后的字符串result。 - mkopriva
2
在字段范围内查找,直到找到具有所需标记的字段。Go语言中标记的用途是什么? 如果您需要频繁使用,请构建一个映射,将标记映射到字段,以便未来的查找变成单个映射索引。 - icza
哇...谢谢...我一直在考虑直接查找的方法,但是找不到。没想到可以使用for循环来检索字段名...哈哈。感谢您的帮助... - Boo Yan Jiong
1
@EliBendersky的回答已添加。 - mkopriva
显示剩余2条评论
2个回答

11
您可以使用reflect包遍历结构体字段并匹配它们的标记值。
func getFieldName(tag, key string, s interface{}) (fieldname string) {
    rt := reflect.TypeOf(s)
    if rt.Kind() != reflect.Struct {
        panic("bad type")
    }
    for i := 0; i < rt.NumField(); i++ {
        f := rt.Field(i)
        v := strings.Split(f.Tag.Get(key), ",")[0] // use split to ignore tag "options" like omitempty, etc.
        if v == tag {
            return f.Name
        }
    }
    return ""
}

另外,正如@icza指出的那样,您可以构建一个映射表,然后使用它进行更快的查找。

https://play.golang.com/p/2zCC7pZKJTz

//                         Human            json       a1     Head
var fieldsByTag = make(map[reflect.Type]map[string]map[string]string)

func buildFieldsByTagMap(key string, s interface{}) {
    rt := reflect.TypeOf(s)
    if rt.Kind() != reflect.Struct {
        panic("bad type")
    }

    if fieldsByTag[rt] == nil {
        fieldsByTag[rt] = make(map[string]map[string]string)
    }
    if fieldsByTag[rt][key] == nil {
        fieldsByTag[rt][key] = make(map[string]string)
    }

    for i := 0; i < rt.NumField(); i++ {
        f := rt.Field(i)
        v := strings.Split(f.Tag.Get(key), ",")[0] // use split to ignore tag "options"
        if v == "" || v == "-" {
            continue
        }
        fieldsByTag[rt][key][v] = f.Name
    }
}

https://play.golang.com/p/qlt_mWsXGju


1

我尝试了其他解决方案,并开发了我的从JSON标记值获取布尔字段值。您可以根据自己的情况轻松更改它。

func GetBooleanFieldValueByJsonTag(jsonTagValue string, s interface{}) bool {
    rt := reflect.TypeOf(s)
    if rt.Kind() != reflect.Struct {
        return false
    }
    for i := 0; i < rt.NumField(); i++ {
        f := rt.Field(i)
        v := strings.Split(f.Tag.Get("json"), ",")[0] // use split to ignore tag "options" like omitempty, etc.
        if v == jsonTagValue {
            r := reflect.ValueOf(s)
            field := reflect.Indirect(r).FieldByName(f.Name)
            return field.Bool()
        }
    }
    return false
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接