保留嵌入式结构的自定义编组
在 Go 中,将一个结构嵌入到另一个结构中是继承功能的常见方法。但是,当嵌入结构具有自定义 MarshalJSON() 方法时,可能会出现问题。本文探讨了这一挑战的解决方案,确保外部结构可以正常编组其字段,同时仍然利用嵌入结构的自定义编组。
考虑以下结构:
type Person struct { Name string `json:"name"` } type Employee struct { *Person JobRole string `json:"jobRole"` }
通常,将 Employee 编组为 JSON 会产生预期的输出:
p := Person{"Bob"} e := Employee{&p, "Sales"} output, _ := json.Marshal(e) fmt.Printf("%s\n", string(output)) // Output: {"name":"Bob","jobRole":"Sales"}
但是,为嵌入的 Person 结构引入自定义 MarshalJSON() 方法会更改此行为:
func (p *Person) MarshalJSON() ([]byte, error) { return json.Marshal(struct{ Name string `json:"name"` }{Name: strings.ToUpper(p.Name)}) }
现在,编组 Employee 只会生成大写的名称:
output, _ := json.Marshal(e) fmt.Printf("%s\n", string(output)) // Output: {"name":"BOB"}
要解决此问题,需要一个可能会尝试将 MarshalJSON() 方法添加到外部 Employee 结构。但是,这种方法需要了解嵌入类型的自定义编组,这可能并不总是实用。
更通用的解决方案涉及直接在外部类型上实现 MarshalJSON():
// Note: not on Person func (e *Employee) MarshalJSON() ([]byte, error) { inner, err := json.MarshalIndent((*e.Person).(*Person), "", " ") if err != nil { return nil, err } b := []byte(strings.Replace(string(inner), "}", "}", -1)) b = append(b, []byte(`,"jobRole":"`+e.JobRole+`"}`)...) return b, nil }
此方法调用嵌入结构的 MarshalJSON() 方法,将结果转换为映射,并添加外部结构的字段以生成所需的 JSON 输出。请注意,它不会操作嵌入结构的自定义编组。
或者,可以使用基于反射的方法:
func (e *Employee) MarshalJSON() ([]byte, error) { v := reflect.ValueOf(e).Elem() vf := v.FieldByName("Person") tmp, err := json.MarshalIndent(vf.Interface(), "", " ") if err != nil { return nil, err } return []byte(strings.Replace(string(tmp), "}", `,"jobRole":"`+e.JobRole+`"}`, -1)), nil }
此方法使用反射来访问嵌入结构的值和字段,无需依赖结构知识即可实现自定义编组。
通过在外部类型上实现 MarshalJSON(),这种方法确保嵌入结构和外部结构的字段都正确编组,保留所需的输出。
以上是如何在 Go 嵌入式结构中保留自定义编组?的详细内容。更多信息请关注PHP中文网其他相关文章!