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

Go自定义JSON序列化:自定义Marshal中用encoder.Encode会栈溢出吗?

问题解答

1. 自定义Marshal中使用encoder.Encode会导致栈溢出吗?

会。因为json.Encoder.Encode内部会调用目标类型的MarshalJSON方法(也就是你自定义的MyForm.MarshalJSON),这会形成无限递归调用:自定义Marshal函数调用Encode,Encode又回头触发你的Marshal逻辑,循环往复直到goroutine栈空间耗尽,最终触发栈溢出错误。

2. 外部与内部调用结果不同的原因

外部调用(第135行)用的是json.MarshalIndent,会正常执行你的自定义Marshal逻辑(无递归时);而内部调用(第173行)触发了无限递归,要么直接栈崩溃,要么在os.Exit(0)强制退出前只输出了部分内容,自然和外部正常执行的结果完全不同。

3. 实现需求的正确方式

要实现MyForm序列化时fields数组每个条目单独一行、整体保持美化格式的效果,不能用递归调用Encoder的方式,正确做法是手动构建JSON结构,示例代码如下:

func (f MyForm) MarshalJSON() ([]byte, error) {
    // 定义辅助结构体,序列化除fields外的基础字段
    type FormAux struct {
        Name   string `json:"name"`
        Method string `json:"method"`
    }

    aux := FormAux{
        Name:   f.Name,
        Method: f.Method,
    }

    // 序列化基础部分,获取带缩进的JSON字节
    auxBytes, err := json.MarshalIndent(aux, "", "  ")
    if err != nil {
        return nil, err
    }

    // 单独处理fields数组:每个Field序列化后单独换行并对齐缩进
    var fieldsBytes []byte
    fieldsBytes = append(fieldsBytes, []byte(`,"fields": [`)...)
    for i, field := range f.Fields {
        fieldBytes, err := json.MarshalIndent(field, "", "  ")
        if err != nil {
            return nil, err
        }
        // 每个字段前添加换行和缩进
        fieldsBytes = append(fieldsBytes, []byte("\n  ")...)
        fieldsBytes = append(fieldsBytes, fieldBytes...)
        // 非最后一个字段添加逗号分隔
        if i != len(f.Fields)-1 {
            fieldsBytes = append(fieldsBytes, ',')
        }
    }
    // 闭合数组和结构体
    fieldsBytes = append(fieldsBytes, []byte("\n]")...)
    // 拼接基础字段和fields部分的JSON
    auxBytes = auxBytes[:len(auxBytes)-1]
    result := append(auxBytes, fieldsBytes...)
    result = append(result, '}')

    return result, nil
}

效果说明

  • 基础字段(name、method)保持正常的美化缩进层级
  • fields数组的每个元素单独占一行,与整体格式对齐
  • 完全避免递归调用,不会出现栈溢出问题

内容的提问来源于stack exchange,提问作者xpt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:14:58