You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用structtag包修改Go结构体Tag后无法保留修改值求助

问题:修改Go结构体字段Tag后无法在外部保留

以下是我编写的Go代码:

package main

import (
    "fmt"
    "reflect"

    "github.com/fatih/structtag"
)

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Address string `json:"address"`
}

func main() {
    p := &Person{
        Name:    "John",
        Age:     30,
        Address: "123 Main St",
    }
    p.setTag("Name","newtag")
    p.read1Tag ("Name")
}

func (p* Person) setTag(fieldName string,tagValue string){
    field, _ := reflect.TypeOf(*p).FieldByName(fieldName)
    tags, _ := structtag.Parse(string(field.Tag))
    tags.Delete("json")
    tag := &structtag.Tag{
        Key:  "json",
        Name: tagValue,
    }
    tags.Set(tag)
    field.Tag = reflect.StructTag(tags.String())
    tag1, _ := tags.Get("json")
    fmt.Println (tag1)
    field.Tag = reflect.StructTag(tags.String())
}

func (p Person) read1Tag (fieldName string) {
    field, _ := reflect.TypeOf(p).FieldByName(fieldName)
    tags, _ := structtag.Parse(string(field.Tag))
    tag, _ := tags.Get("json")
    fmt.Println (tag)
}

我想要修改Person结构体中Name字段的json tag,代码在setTag函数内成功修改了tag,但从main函数中读取时仍然显示旧的tag(我已在两个函数内都打印了tag)。我已经使用了指针接收器,请问如何让修改后的tag在函数外也能保留?


解决方案

问题核心在于:Go语言中结构体的类型信息(包括字段Tag)是编译期确定的全局只读数据。你在setTag里通过reflect.TypeOf(*p).FieldByName拿到的field是类型信息的副本,修改这个副本的Tag字段只会影响当前副本,不会改变原结构体类型的定义,所以外部读取时还是原来的Tag。

要实现动态修改Tag并在外部生效的效果,不能直接修改结构体类型的Tag,而是需要自己维护动态Tag的映射,并在需要使用Tag的逻辑中优先使用这个映射。以下是两种可行方案:

方案1:给结构体添加自定义Tag映射字段

在Person结构体中新增成员变量存储动态修改的Tag,读写时优先使用这个映射:

package main

import (
    "fmt"
    "reflect"

    "github.com/fatih/structtag"
)

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Address string `json:"address"`
    customTags map[string]string // 存储动态Tag:键为字段名,值为json tag值
}

func main() {
    p := &Person{
        Name:    "John",
        Age:     30,
        Address: "123 Main St",
        customTags: make(map[string]string),
    }
    p.setTag("Name","newtag")
    p.read1Tag("Name")
}

func (p* Person) setTag(fieldName string, tagValue string){
    // 先验证字段是否存在
    if _, ok := reflect.TypeOf(*p).FieldByName(fieldName); ok {
        p.customTags[fieldName] = tagValue
        fmt.Println(&structtag.Tag{Key: "json", Name: tagValue})
    }
}

func (p Person) read1Tag(fieldName string) {
    // 优先读取自定义映射的Tag
    if val, ok := p.customTags[fieldName]; ok {
        fmt.Println(&structtag.Tag{Key: "json", Name: val})
        return
    }
    // 无自定义Tag时读取原结构体Tag
    field, _ := reflect.TypeOf(p).FieldByName(fieldName)
    tags, _ := structtag.Parse(string(field.Tag))
    tag, _ := tags.Get("json")
    fmt.Println(tag)
}

方案2:自定义JSON序列化逻辑(针对JSON场景)

如果修改Tag是为了影响JSON序列化/反序列化,可以自定义MarshalJSON方法,在序列化时使用动态Tag:

package main

import (
    "encoding/json"
    "fmt"
    "reflect"

    "github.com/fatih/structtag"
)

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Address string `json:"address"`
    customTags map[string]string
}

func main() {
    p := &Person{
        Name:    "John",
        Age:     30,
        Address: "123 Main St",
        customTags: make(map[string]string),
    }
    p.setTag("Name","newtag")
    p.read1Tag("Name")
    // 测试JSON序列化
    data, _ := json.Marshal(p)
    fmt.Println(string(data)) // 输出 {"newtag":"John","age":30,"address":"123 Main St"}
}

func (p* Person) setTag(fieldName string, tagValue string){
    if _, ok := reflect.TypeOf(*p).FieldByName(fieldName); ok {
        p.customTags[fieldName] = tagValue
        fmt.Println(&structtag.Tag{Key: "json", Name: tagValue})
    }
}

func (p Person) read1Tag(fieldName string) {
    if val, ok := p.customTags[fieldName]; ok {
        fmt.Println(&structtag.Tag{Key: "json", Name: val})
        return
    }
    field, _ := reflect.TypeOf(p).FieldByName(fieldName)
    tags, _ := structtag.Parse(string(field.Tag))
    tag, _ := tags.Get("json")
    fmt.Println(tag)
}

// 自定义MarshalJSON方法,使用动态Tag生成JSON字段
func (p Person) MarshalJSON() ([]byte, error) {
    result := make(map[string]interface{})
    t := reflect.TypeOf(p)
    v := reflect.ValueOf(p)

    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        // 跳过自定义Tag字段
        if field.Name == "customTags" {
            continue
        }
        // 获取JSON键:优先用自定义Tag,否则用原结构体Tag
        jsonKey := field.Tag.Get("json")
        if customKey, ok := p.customTags[field.Name]; ok {
            jsonKey = customKey
        }
        result[jsonKey] = v.Field(i).Interface()
    }
    return json.Marshal(result)
}

内容的提问来源于stack exchange,提问作者Castracucchi Davide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 14:22:44