Golang自定义JSON Unmarshal未解析部分子结构,如何指定解析?
问题
定义了父结构体ResponseParent,它嵌入了ResponseA、ResponseB两个子结构体,还包含PageC字段。为ResponseA编写自定义UnmarshalJSON函数后,发现ResponseB结构体和PageC字段未被解析,如何编写自定义Unmarshal以仅解析指定结构?
相关代码:
type ResponseA struct { PageA int `json:"pageA"` EntriesA []string `json:"entriesA"` } type ResponseB struct { PageB int `json:"pageB"` EntriesB []string `json:"entriesB"` } type ResponseParent struct { ResponseA ResponseB PageC int `json:"pageC"` } func (r *ResponseA) UnmarshalJSON(data []byte) error { // UnMarshal ResponseA structure } func main() { jsonStr := `{"pageA": 1, "entriesA": ["classA"], "pageB": 2, "entriesB": ["classC","classD"], "pageC":3}` // str := `{"page": 1, "entries": ["classA", "classB"]}` var res *ResponseParent json.Unmarshal([]byte(jsonStr), &res) entriesA := res.EntriesA pageA := res.PageA entriesB := res.EntriesB pageB := res.PageB pageC := res.PageC fmt.Println("========Response A==========a") fmt.Println("PageA: %v", pageA) fmt.Println("EntriesA: %v", entriesA) fmt.Println("========Response B==========a") fmt.Println("PageB: %v", pageB) fmt.Println("EntriesB: %v", entriesB) fmt.Println("PageC: %v", pageC) }
输出结果:
========Response A==========a PageA: %v 1 EntriesA: %v [classA] ========Response B==========a PageB: %v 0 EntriesB: %v [] PageC: %v 0
原因分析
当为ResponseA实现自定义UnmarshalJSON后,Go的json包解析ResponseParent时,会优先调用嵌入的ResponseA的自定义反序列化方法,但这个方法只处理了ResponseA自身字段,没有把剩余JSON数据交给ResponseParent去解析ResponseB和PageC,导致这部分字段无法被正确赋值。
解决方案
思路一:为ResponseParent实现自定义UnmarshalJSON
直接在父结构体层面处理反序列化,分别解析各个字段,精准控制每个部分的解析逻辑:
func (rp *ResponseParent) UnmarshalJSON(data []byte) error { // 解析ResponseA部分 var ra ResponseA if err := json.Unmarshal(data, &ra); err != nil { return err } rp.ResponseA = ra // 解析ResponseB部分 var rb ResponseB if err := json.Unmarshal(data, &rb); err != nil { return err } rp.ResponseB = rb // 解析PageC字段 var pc struct { PageC int `json:"pageC"` } if err := json.Unmarshal(data, &pc); err != nil { return err } rp.PageC = pc.PageC return nil }
思路二:修改ResponseA的自定义UnmarshalJSON方法(局限性说明)
如果必须保留ResponseA的自定义反序列化,需要借助临时结构体避免递归调用,先解析自身字段,但这种方式无法自动处理ResponseParent的其他字段:
func (r *ResponseA) UnmarshalJSON(data []byte) error { // 定义临时结构体,避免递归调用自定义UnmarshalJSON type TempResponseA ResponseA var temp TempResponseA if err := json.Unmarshal(data, &temp); err != nil { return err } *r = ResponseA(temp) // 注意:此方法仅能保证ResponseA字段正常解析,无法处理ResponseParent中的ResponseB和PageC return nil }
优先推荐思路一,直接在父结构体上实现自定义反序列化,能完全掌控所有字段的解析流程,避免局限性。
内容的提问来源于stack exchange,提问作者user2830260
相关产品推荐
相关产品推荐

