使用方法
- 「JSON 源数据」默认已经写好一段五字段的示例:字符串、整数、浮点、字符串数组与嵌套对象各一个。
- 「根结构体名」默认
Root,另有 Response、Data、Payload、Item 四个常用名可选。它只影响最外层那一行,不影响嵌套层。 - 「缩进空格数」默认 4,范围 1 到 8。它决定每层字段前的空格数,嵌套每深一层多一份缩进。
- 「标签风格」默认带 json 标签,即每个字段后面挂上标签;选 omitempty 会写成 omitempty 形式;选不带标签则只输出字段名与类型。
- 按 Ctrl+Enter(Mac 上 Cmd+Enter)或在缩进输入框里按回车即可生成,不必去点按钮。
- 结果区第一行统计顶层字段数与叶子字段数,下面是可直接粘进
.go文件的声明原文,最后一行重复统计与最深字段路径。 - 下方是二十行类型推导速查表,默认显示 12 行,点「加载更多」展开余下 8 行;「导出 CSV」存成带字节序标记的文件。
- 源数据为空、括号不配对、冒号缺失、键没加双引号、缩进不是 1 到 8 的整数,都会给出写明位置或字段名与原因的具体提示。
这个JSON转Go结构体工具能解决什么
对接一个只给了示例响应的接口时,第一件事通常是照着 JSON 手敲 Go 结构体:几层嵌套、几十个字段,敲完还要逐个补标签。这活儿不复杂但极易出错,错的地方又往往在标签拼写上。这一页做的是把示例 JSON 直接折成一份类型声明,字段类型按原始文本推出来,标签一次性挂齐。
第一类是接口响应建模。默认示例五个顶层字段,折出来的结果里 Name 是 string、Age 是 int、Score 是 float64、Tags 是 []string、Addr 是带一个 City 字段的匿名 struct,标签与原始键名逐字对应。
第二类是避开 int 与 float64 的判定坑。JSON 只有一个数字类型,Go 有两个。判定必须看字面写法:带小数点或指数的才推成 float64,否则推成 int。所以 30 是 int、95.5 是 float64,而 1.0 因为写了小数点也是 float64。
第三类是嵌套结构的取舍。对象落成匿名 struct 而不是命名类型,好处是复制一份就能用、不必补一堆 type 声明;代价是同一形状出现两次会生成两份、无法复用。要复用就得自己把匿名 struct 提出来命名,本页不做这一步。
还有一类边界要说清:推导只看当前这一份样本。样本里某个字段是 null,就推不出真实类型;样本里缺字段,生成的结构体也缺。多份样本要靠人工合并。
计算原理与变量说明
整页分三步:先把源文本切成带类型标记的节点,再给每个节点算出一个 Go 类型串,最后按缩进拼成声明。关键在于第一步必须保留数字的字面写法,因为「是不是浮点」这个信息在 JSON.parse 之后就没了。
为什么不能只靠 JSON.parse。JSON.parse 把 42.0 读成数值 42,与 42 完全一样,之后怎么判断都分不出来。而 Go 侧 float64 与 int 是两种类型,写错会导致反序列化失败或精度丢失。所以本页自己写扫描器,遇到数字时把原始片段一起带回,再看里面有没有小数点或 e/E。
| 量 | 符号 | 算式 / 规则 | 默认值 |
|---|---|---|---|
| 根结构体名 | ROOT | 下拉选择,只能是字母开头的标识符 | Root |
| 缩进空格数 | ind | 第 n 层缩进 = ind × n | 4 |
| 标签风格 | TAG | json / omitempty / none | json |
| 浮点判定 | isF | raw 含小数点或 e/E 即浮点 | — |
| 数组元素类型 | T | 逐个比对,全同取 T,否则 interface{} | — |
| 顶层字段数 | top | 根对象子键个数 | 5 |
| 叶子字段数 | leaf | 递归到底的非容器节点数 | 6 |
字段名为什么要转大驼峰。Go 的 encoding/json 只序列化首字母大写的字段,小写字段会被静默跳过——不报错,只是结果里少一截。所以 user_name 要变成 UserName 才能被导出,原名则靠 json 标签留在序列化的键上。
null 一律推成 interface{}。样本里的 null 只说明这一次取值为空,真实类型可能是字符串、数字、对象或数组,任何一种猜测都可能错。空数组同理,推成 []interface{}。
标签里的键名原样保留。标签写成 json 指向原名而不是驼峰名,这样线上接口的字段名与生成的声明一一对应,不会因为改名而对不上。
完整示例(数值仅作演示)
默认示例五个顶层字段,逐个走一遍推导:name 是带双引号的文本,推成 string;age 写作 30,没有小数点也没有指数,推成 int;score 写作 95.5,含小数点,推成 float64;tags 是两个字符串元素,类型一致,推成切片;addr 是含 city 的对象,落成匿名 struct。
输入:{"name":"张三","age":30,"score":95.5,"tags":["a","b"],"addr":{"city":"北京"}}
推导:name → string;age → int;score → float64;
tags → []string;addr → struct { City string }
输出:type Root struct { ... }(共 5 个顶层字段)
把「根结构体名」换成 Response,只有最外层那一行变成 type Response struct,Addr 里的匿名 struct 不受影响。把缩进改成 2,顶层字段前的空格从 4 个变成 2 个,嵌套层的 City 从 8 个变成 4 个。
把「标签风格」换成 omitempty,每个标签都写成 omitempty 形式,序列化时空值字段会被跳过;换成不带标签,行尾的标签整体消失,只剩字段名与类型。三项设置互不影响,可以任意组合。
类型推导速查表
下表列出二十种常见取值推导出的 Go 类型,全部由页面自己的扫描器与类型函数生成,可以逐行对照。判定浮点只看字面写法,不看数值大小。
| JSON 片段 | 推导类型 | 判定依据 |
|---|---|---|
| true | bool | 字面量 true |
| false | bool | 字面量 false |
| 0 | int | 整数且无小数点 |
| 30 | int | 整数且无小数点 |
| -7 | int | 负号不改变整型判定 |
| 95.5 | float64 | 含小数点 |
| -0.25 | float64 | 含小数点 |
| 1.0 | float64 | 含小数点,值虽等于 1 |
| 1e3 | float64 | 含指数符号 e |
| -2.5E-2 | float64 | 含小数点与大写 E |
| "a" | string | 带双引号即字符串 |
| "" | string | 空串也是字符串 |
| "30" | string | 带引号的数字仍是字符串 |
| [] | []interface{} | 空数组无法判定元素类型 |
| ["a","b"] | []string | 元素类型全部为 string |
| [1,2] | []int | 元素类型全部为 int |
| [true,false] | []bool | 元素类型全部为 bool |
| [1,"a"] | []interface{} | 元素类型不一致 |
| {} | struct {} | 空对象没有可推导的字段 |
| {"city":"北京"} | struct { City string } | 对象落成匿名 struct |
第二张表给出浮点判定的四个边界:写法带小数点或 e/E 就是 float64,两者都没有才是 int。
| 原始文本 | 含小数点 | 含 e/E | 推导类型 |
|---|---|---|---|
| 30 | 否 | 否 | int |
| 1.0 | 是 | 否 | float64 |
| 1e3 | 否 | 是 | float64 |
| -2.5E-2 | 是 | 是 | float64 |
结果边界、舍入与适用说明
- 源数据整段为空时提示「JSON 源数据这一栏是空的」,不会输出空声明;清空后点「生成结构体」会自动填回示例。
- 花括号或方括号不配对时,提示缺少的是哪一种、大致在第几个字符,不尝试容错修复。
- 对象的键没有用双引号包裹、或键值之间缺冒号,都会指出具体字符位置——手敲 JSON 最常见的两处笔误。
- 数字写成 01、.5、+1 这类不合规范的写法会被拦下,不按 JS 的习惯静默解析。
- 缩进必须是 1 到 8 的整数,填 0、9、2.5 或留空会分别给出提示。
- 整数一律推成 int 而非 int64:超过三十二位范围的数值请在生成后自行改成 int64,本页不预测取值范围。
- 推导只基于当前这一份样本,缺失字段与 null 值都无法凭空补全,多份样本需要人工合并。
- 页面不联网、不写本地存储;导出的 CSV 带字节序标记,Excel 打开不乱码。
常见问题
为什么字段名要转大驼峰?
Go 的 encoding/json 只处理首字母大写的字段,小写字段会被静默跳过,不报错但结果里缺失。原名通过 json 标签保留,序列化出的键名不受影响。
1.0 这种值该推成什么?
推成 float64。规则只看字面写法:带小数点或指数符号的就是浮点,不带两者才是 int。所以 1 是 int、1.0 是 float64、1e0 也是 float64,三者数值完全相等但类型不同。
null 为什么推成 interface{}?
样本里的 null 只说明这一次取值为空,真实类型可能是字符串、数字、对象或数组,任何一种猜测都可能错。interface{} 是最保守的选择,拿到非空样本后再改成具体类型。
数组元素类型不一致会怎样?
整列退回 []interface{}。Go 的切片元素类型必须统一,混合类型数组无法表达成 []T,只能退到空接口,取值时再做类型断言。
嵌套对象为什么不拆成命名类型?
匿名 struct 复制一份就能用,不必补一堆 type 声明,这是本页的默认取舍;代价是同一形状出现两次会生成两份、无法复用。需要复用时把匿名 struct 提出来命名即可。
很大的整数会溢出吗?
本页不会溢出,但也只推成 int。数字一律先按字面判定:不带小数点与指数就是 int,数值超过三十二位范围时请手动改成 int64,否则反序列化会溢出。
带连字符或下划线的字段名怎么处理?
先按非字母数字的连续段切开,每段首字母大写再拼回去。所以 user_name 与 user-name 都会变成 UserName,以数字开头的键会在前面补一个 F。
输入的数据会上传到服务器吗?
不会。扫描、推导、拼装与导出全部在本页 JavaScript 里完成,没有发起任何网络请求,也不写入浏览器存储,刷新即恢复默认示例。
相关工具
- JSON格式化工具:先整理缩进再看结构。
- JSON校验工具:粘贴前先确认语法合法。
- CSV转JSON转换器:表格数据先转 JSON 再生成结构体。
- JSON转XML转换器:同一份数据的另一种目标格式。
- HTML格式化:接口返回 HTML 时的整理工具。
- 开发者工具:查看全部开发者工具。