如何正确设计 Go 结构体以解析嵌套 JSON(含转义字符串问题)

本文详解 Go 中 struct 标签与 JSON 反序列化的正确用法,重点解决因服务端错误地将 JSON 对象序列化为字符串导致 []Spec 为空的典型问题,并提供无需字符串替换的安全解析方案。

本文详解 Go 中 struct 标签与 JSON 反序列化的正确用法,重点解决因服务端错误地将 JSON 对象序列化为字符串导致 `[]Spec` 为空的典型问题,并提供无需字符串替换的安全解析方案。

在 Go 中使用 json.Unmarshal 解析结构化数据时,struct 字段标签(如 `json:"name"`)必须与 JSON 键名严格匹配,且类型需兼容。但本例的根本问题并非标签错误——而是上游数据格式异常:"spec" 字段实际是一个字符串数组(如 ["{\"name\":\"bla_bla\",...}"]),而非预期的对象数组([{"name":"bla_bla",...}])。这导致 Go 尝试将字符串直接反序列化为 Spec 结构体失败,Specs 字段保持零值(空切片)。

✅ 正确做法:自定义反序列化逻辑(推荐)

避免危险的字符串替换(易出错、破坏 JSON 完整性),应通过实现 UnmarshalJSON 方法手动处理嵌套字符串:

type Products struct {
    Product string `json:"product"`
    Specs   []Spec `json:"spec"`
}

type Spec struct {
    Name string `json:"name"`
    Info Inf    `json:"info"`
}

type Inf struct {
    Color string `json:"color"`
    Year  int    `json:"year"`
}

// 为 Specs 字段实现自定义反序列化
func (p *Products) UnmarshalJSON(data []byte) error {
    // 先定义一个临时结构体,将 spec 字段暂存为字符串切片
    type Alias Products // 防止递归调用
    aux := &struct {
        Specs []string `json:"spec"`
        *Alias
    }{
        Alias: (*Alias)(p),
    }
    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }

    // 逐个解析 spec 字符串为 Spec 对象
    p.Specs = make([]Spec, 0, len(aux.Specs))
    for _, s := range aux.Specs {
        var spec Spec
        if err := json.Unmarshal([]byte(s), &spec); err != nil {
            return fmt.Errorf("failed to unmarshal spec %q: %w", s, err)
        }
        p.Specs = append(p.Specs, spec)
    }
    return nil
}

使用方式保持简洁:

c := `{"product":"car","spec":["{\"name\":\"bla_bla\",\"info\":{\"color\":\"black\",\"year\":1991}}"]}`
var products Products
if err := json.Unmarshal([]byte(c), &products); err != nil {
    log.Fatal(err)
}
fmt.Println(products.Product)           // "car"
fmt.Println(products.Specs[0].Name)     // "bla_bla"
fmt.Println(products.Specs[0].Info.Year) // 1991

⚠️ 注意事项与最佳实践

通过自定义 UnmarshalJSON,你既能稳健应对不规范输入,又保持了代码的可维护性与安全性——这才是 Go “explicit is better than implicit” 哲学的体现。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。