Jason Pan

Go JSON 转换技巧:解决字段类型不一致

潘忠显 / 2025-12-10


对接外部 API 时,开发者经常会遇到一个令人头疼的问题:外部系统返回的 JSON 数据,其字段类型与我们 Go 结构体中预期的类型不一致。

典型地,API 可能将原本应该是数值的,错误地或者出于历史原因地包装在 JSON 字符串中返回(例如,"age": "30" 而不是标准的 "age": 30)。

如果直接尝试将这些 JSON 字段解码(Unmarshal)到 Go 结构体的 intfloat64 字段中,Go 语言的 encoding/json 包会因为类型不匹配而报错。你使用 string 类型来定义,又每次都需要转换。

其实可以利用 Go 语言结构体标签(Tag)提供的强大功能,在不修改 Go 结构体内部类型(保持 int 等强类型)的前提下,兼容外部这种不规范的 JSON 格式

一、使用 ,string 强制转换类型

在结构体字段的 json 标签后面添加 ,string 标签是解决上述问题的核心方法。

它指示 encoding/json 包在处理这个字段时,将 Go 结构体中的字段值视为一个 JSON 字符串来处理。

例如,以下定义允许 Go 结构体中的 Age 保持 int 类型,但告知 JSON 编码器和解码器,在 JSON 世界中,它对应的是一个字符串。

type Data struct {
    Name string `json:"name"`
    // Age 是 int 类型,但使用字符串进行编解码
    Age  int    `json:"age,string"` 
}

编解码效果

编码(Marshal: Go Struct -> JSON):当 Go 结构体字段 Age 的值为 30(整数)时,编码器会将其转换为 JSON 字符串 “30”。最终 JSON 输出将是:{"name":"Alice","age":"30"}

解码(Unmarshal: JSON -> Go Struct):解码器会读取 JSON 输入中的 “age”:“45” 字符串。它会尝试将字符串中的内容 "45" 解析成一个整数,并成功赋值给 Go 结构体的 Age 字段(int(45))。

适用范围

这个 ,string 标签的强大之处在于,它适用于所有 Go 的基础类型,只要该类型有对应的标准库函数(如 strconv 包中的 ParseFloatParseBool 等)可以将其从字符串解析出来。比如将"3.14" 用于 float64 等类型,接受 "true""false" 用于 bool 类型。

但是,请注意,,string 不能直接用于复杂的复合类型,比如结构体(Struct)或切片(Slice),因为它只能处理扁平化的数据。

二、JSON的其他常用标签

除了 ,string 之外,encoding/json 包还提供了其他几种强大且常用的标签技巧,可以极大地增强结构体的灵活性。

如果定义一个结构体,不使用 json: 标签,在Marshal的时候,会只以同名的方式,产生 JSON 的 key,并且这里只有大些开头的字段——被导出的。