为了账号安全,请及时绑定邮箱和手机立即绑定

如何将嵌套结构中的字段设置为零值?

如何将嵌套结构中的字段设置为零值?

Go
开心每一天1111 2022-04-26 14:32:01
假设我有一个Thing1我想要的 struct 实例json.Marshaltype Thing1 struct {    A string `json:"a,omitempty"`    B int    `json:"b,omitempty"`    C Thing2 `json:"c,omitempty"`}type Thing2 struct {    D bool `json:"d,omitempty"`    E int  `json:"e,omitempty"`}...thing1 := Thing1{    A: "test",    B: 42,    C: Thing2{D: true, E: 43},}您将如何编写一个函数,该函数采用任何结构的实例和要编辑的字段列表并返回传入对象的克隆(或只是变异),但将已编辑的字段设置为零值?redact(thing1, []string{"B", "D"})thing1 == Thing1{    A: "test",    B: 0,    C: Thing2{D: false, E: 43},}我不能json:"-"用作字段标签,因为我正在使用的查询语言(Dgraph)需要当前的标签。编辑:不在示例中,但如果适用,还应编辑数组内的对象
查看完整描述

1 回答

?
aluckdog

TA贡献1847条经验 获得超7个赞

使用反射来操作结构字段的值。以下是我在评论中写的概念证明。由于这只是一个 poc,您可能需要调整/修改代码以满足您的需求。


这个函数改变原始数据。代码是不言自明的。


func redact(target interface{}, fieldsToModify []string) {

    // if target is not pointer, then immediately return

    // modifying struct's field requires addresable object

    addrValue := reflect.ValueOf(target)

    if addrValue.Kind() != reflect.Ptr {

        return

    }


    // if target is not struct then immediatelly return

    // this might need to be modified as per your needs

    targetValue := addrValue.Elem()

    targetType := targetValue.Type()

    if targetType.Kind() != reflect.Struct {

        return

    }


    // loop the fields

    for i := 0; i < targetType.NumField(); i++ {

        fType := targetType.Field(i)

        fValue := targetValue.Field(i)


        // if the field type is struct, then call redact() recursively

        if fValue.Kind() == reflect.Struct {

            redact(fValue.Addr().Interface(), fieldsToModify)

            continue

        } 


        // if the field is slice, loop then call redact() recursively

        if fValue.Kind() == reflect.Array || fValue.Kind() == reflect.Slice {

            for i := 0; i < fValue.Len(); i++ {

                redact(fValue.Index(i).Addr().Interface(), fieldsToModify)

            }

            continue

        }


        // loop the fieldsToModify

        for _, fieldToModify := range fieldsToModify {

            if fieldToModify == fType.Name && fValue.CanSet() {

                fValue.Set(reflect.Zero(fType.Type))

            }

        }

    }

}

第一个参数中的redact()函数指针数据,因为修改字段需要可添加对象。


type Thing2 struct {

    D bool `json:"d,omitempty"`

    E int  `json:"e,omitempty"`

}


type Thing1 struct {

    A string   `json:"a,omitempty"`

    B int      `json:"b,omitempty"`

    C Thing2   `json:"c,omitempty"`

    H []Thing2 `json:"h,omitempty"`

}


thing1 := Thing1{

    A: "test",

    B: 42,

    C: Thing2{D: true, E: 43},

    H: []Thing2{Thing2{D: true, E: 43}},

}


fmt.Printf("before: %#v \n", thing1)

// before: main.Thing1{A:"test", B:42, C:main.Thing2{D:true, E:43}, H:[]main.Thing2{main.Thing2{D:true, E:43}}} 


redact(&thing1, []string{"B", "D"})

fmt.Printf("after: %#v \n", thing1)

// after: main.Thing1{A:"test", B:0, C:main.Thing2{D:false, E:43}, H:[]main.Thing2{main.Thing2{D:false, E:43}}} 

游乐场: https: //play.golang.org/p/wy39DGdSVV7


查看完整回答
反对 回复 2022-04-26
  • 1 回答
  • 0 关注
  • 108 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信