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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:54:53