如何把 JSON 快速转成 Go struct(含 json tag 与嵌套类型)
对接第三方 API,返回一大段 JSON。你不想手写几十个字段的 Go struct——既慢又容易拼错 tag。能不能自动转?
能。下面讲清楚 JSON → Go struct 的类型映射规则,以及怎么一键生成带 json tag 的代码。
JSON 类型到 Go 类型的映射
| JSON 类型 | Go 类型 | 备注 |
|---|---|---|
对象 {} | struct {…} | 嵌套结构体 |
数组 [] | 切片 []T | 元素类型取数组内容推断 |
字符串 "a" | string | |
| 数字(无小数) | int64 / float64 | 取决于是否有小数点 |
| 数字(有小数) | float64 | |
布尔 true/false | bool | |
null | 指针或 interface{} | 建议用指针 *T 区分「零值」与「未设置」 |
| 混合类型数组 | []interface{} | 尽量避免 |
关键坑:数字与 null
Go 没有「可空的基础类型」。如果字段可能是 null,直接写成 int 反序列化会报错,应写成指针:
type User struct {
Name string `json:"name"`
Age *int `json:"age"` // 可能为 null
Score *float64 `json:"score"`
}
一步步生成(无需装任何插件)
用本站 JSON 转 Go 工具,在浏览器本地完成,JSON 不上传:
- 打开 JSON 转 Go。
- 粘贴你的 JSON(可以是对象或数组)。
- 配置选项:
- JSON Tag:默认 保留原始键名,让
json:"…"与样例线上键一致;只有故意改写线上形态时才选snake_case/camelCase;无 json 标签则不生成 tag。 - 导出样式:Go 字段用 PascalCase 或 camelCase(导出字段名仍会首字母大写,以便
encoding/json可见)。 - 根类型名(如
Response、User)以及可选的omitempty。
- JSON Tag:默认 保留原始键名,让
- 输入变化时输出即时更新——把
struct代码复制进项目即可。 - 如果还要转成其他语言,可再用 JSON 转 TypeScript 或 JSON 转 Java。
一个完整例子
输入 JSON:
{
"id": 1024,
"name": "Alice",
"isActive": true,
"tags": ["go", "api"],
"profile": {
"age": 30,
"city": "Shanghai"
}
}
工具生成的 Go 代码:
type Profile struct {
Age int `json:"age"`
City string `json:"city"`
}
type Response struct {
ID int `json:"id"`
Name string `json:"name"`
IsActive bool `json:"isActive"`
Tags []string `json:"tags"`
Profile Profile `json:"profile"`
}
进阶建议
- 先格式化再转换:杂乱的 JSON 先用 JSON 格式化工具 整理,类型推断更准。
- 区分零值与缺失:对外接口字段多用指针,避免把「未返回」误判为「0 / 空串」。
- 时间字段:JSON 里的时间通常是 RFC3339 字符串,Go 里用
time.Time并确认jsontag 与格式一致。 - 大写导出:Go 字段必须大写才能被
encoding/json序列化,转换工具默认已处理,手写时别漏。
常见问题
Q:数组里元素类型不一致怎么办?
转成 []interface{},你自己再断言。若能改接口,尽量让元素结构统一。
Q:数字有时是整数有时是小数?
不确定时用 float64;若确定是整数,手动改成 int64。
Q:嵌套太深,生成的 struct 太多?
可以考虑用 map[string]interface{} 临时接收,再按需定义结构体,或分层转换。
Q:要生成带 omitempty 的 tag 吗?
视场景。写请求体时 omitempty 能省掉零值字段;读响应体时通常不需要,避免把「缺失」当成「零值」。
Go 三坑:时间、null、接口
time.Time 序列化为 RFC 3339 字符串,反序列化只认这个格式——API 吐 epoch 毫秒(JS 默认)就要自定义类型或 int64 加转换。null 进 string 字段静默变空串(无报错、遗漏式数据损坏);进 *string 才是正确的 nil——API 里每个可空字段都该生成指针。interface:异构数组把类型开关推进每个消费者;更干净的模式是两个显式字段配 json.RawMessage 按需解码。
json tag 必须贴合线上键(而不是迁就 Go 审美)
典型踩坑:粘贴 camelCase JSON(userName),却把 tag 下拉设成 snake_case。旧默认会把 tag 改写成 user_name,json.Unmarshal 于是永远填零值——编译不报错,只是静默丢数据。ToolVault 现在默认 保留原始键名:tag 字符串等于样例里的 JSON 键。只有在你故意发射另一种约定时(例如 Go 字段保持惯用写法,但请求体必须是 snake),才用 snake/camel 改写。
样例里的大整数走无损路径(无小数点时倾向 int64);若中间又经过别的编辑器,仍要核对是否超过 JS 安全整数。
值得手工加的三个 tag
omitempty 在可选字段上——否则响应回显零值(count:0)让消费者分不清「值为零」和「字段缺席」;,string 加在遗留 API 按字符串发数字的字段上(JS 大数恐惧症的产物);命名分离——Go 惯例要 UserID 而 JSON 说 userId,让 tag 承担不匹配,不要为此起非惯用 Go 名。版本化 API 每版一套 struct,好过 interface 汤。
往返测试生成的类型
能编译的 struct 不等于能往返:把原始 JSON 过 json.Unmarshal 再 json.Marshal,规范化键序后字节比对。差异精确出现在 schema 与 Go 分歧处——null 处理、数字精度(float64 静默吞大 int64——ID 用 json.Number)、未知字段丢弃。这十行测试属于每个带 schema 的服务的 CI。
小结
JSON 转 Go struct = 按类型映射规则生成带 json tag 的结构体,注意 null 用指针、数字类型要选对。用本站的 JSON 转 Go 工具 在本地一键生成,JSON 不上传,更适合处理含敏感字段的接口数据。
实现注记
同站 JSON 转 TypeScript 工具修过的一个坑对类型生成都有参考价值:异构数组曾静默丢弃第一个元素之后的内容,后来改为产出联合元素类型,元素类型名按单数化键名生成(users → User)。Go 没有 union 可退,给异构数组建 struct 更要在样例里多放几条数据,别让第一条替整批表态。
相关工具
相关文章
正则表达式匹配不上?排查这 6 个常见坑
正则表达式不匹配、regex匹配失败时如何排查?本文详解贪婪量词、标志位遗漏、特殊字符转义、环视断言、换行符处理、Unicode属性6大常见坑,附前后对比示例,帮你快速定位正则调试问题。
Hydration failed / Text content does not match 报错怎么解决?
Next.js/React SSR 最常见的水合报错完整指南:为什么服务端和客户端渲染不一致、时间戳/随机值/localStorage 三大来源、suppressHydrationWarning 的正确用法,配本站工具定位差异。
Cannot read properties of undefined (reading 'map') 报错怎么解决?
React/前端最常见运行时报错的完整排查指南:为什么 undefined.map 会报错、接口数据异步加载的正确处理、可选链与默认值防御、空状态渲染,配本站 JSON 工具实测定位。