当前位置: > > > > 如何将嵌套结构中的字段设置为零值?
如何将嵌套结构中的字段设置为零值?
来源:stackoverflow
2024-04-25 18:30:37
0浏览
收藏
学习知识要善于思考,思考,再思考!今天米云小编就给大家带来《如何将嵌套结构中的字段设置为零值?》,以下内容主要包含等知识点,如果你正在学习或准备学习Golang,就都不要错过本文啦~让我们一起来看看吧,能帮助到你就更好了!
问题内容
假设我有一个 struct thing1 实例,我想要 json.marshal
type 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},
}
您将如何编写一个函数,该函数采用任何结构体的实例和要编辑的字段列表,并返回传入对象的克隆(或只是变异),但将编辑的字段设置为零值? p>
redact(thing1, []string{"B", "D"})
thing1 == Thing1{
A: "test",
B: 0,
C: Thing2{D: false, E: 43},
}
我无法使用 json:"-" 作为字段标记,因为我正在使用的查询语言 (dgraph) 需要当前的字段标记。
编辑:不在示例中,但如果适用,也应编辑数组内的对象
解决方案
使用reflect来操作struct字段的值。以下是我在评论中所写内容的概念证明。由于这只是一个 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}}}
演示:
今天带大家了解了的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注米云公众号,一起学习编程~
