JSON转Go结构体生成器

把一段 JSON 直接折成 Go 的类型声明:string 转 string,不带小数点与指数的整数转 int,带小数点或指数的转 float64,true 与 false 转 bool,null 转 interface{},数组元素类型一致时才写成切片,对象落成匿名 struct。字段名统一转大驼峰并挂上 json 标签,支持缩进宽度设置与批量转换,全程本地计算不上传。

按原始文本判定浮点:带小数点或 e/E 的数字推成 float64,其余整数推成 int。

默认示例含字符串、整数、浮点、字符串数组与嵌套对象五类字段。输入框被清空时点「生成结构体」会自动填回示例;在缩进输入框里按 Enter 也会重新生成。

使用方法

  1. 「JSON 源数据」默认已经写好一段五字段的示例:字符串、整数、浮点、字符串数组与嵌套对象各一个。
  2. 「根结构体名」默认 Root,另有 Response、Data、Payload、Item 四个常用名可选。它只影响最外层那一行,不影响嵌套层。
  3. 「缩进空格数」默认 4,范围 1 到 8。它决定每层字段前的空格数,嵌套每深一层多一份缩进。
  4. 「标签风格」默认带 json 标签,即每个字段后面挂上标签;选 omitempty 会写成 omitempty 形式;选不带标签则只输出字段名与类型。
  5. 按 Ctrl+Enter(Mac 上 Cmd+Enter)或在缩进输入框里按回车即可生成,不必去点按钮。
  6. 结果区第一行统计顶层字段数与叶子字段数,下面是可直接粘进 .go 文件的声明原文,最后一行重复统计与最深字段路径。
  7. 下方是二十行类型推导速查表,默认显示 12 行,点「加载更多」展开余下 8 行;「导出 CSV」存成带字节序标记的文件。
  8. 源数据为空、括号不配对、冒号缺失、键没加双引号、缩进不是 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 × n4
标签风格TAGjson / omitempty / nonejson
浮点判定isFraw 含小数点或 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 片段推导类型判定依据
truebool字面量 true
falsebool字面量 false
0int整数且无小数点
30int整数且无小数点
-7int负号不改变整型判定
95.5float64含小数点
-0.25float64含小数点
1.0float64含小数点,值虽等于 1
1e3float64含指数符号 e
-2.5E-2float64含小数点与大写 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

结果边界、舍入与适用说明

常见问题

为什么字段名要转大驼峰?

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 里完成,没有发起任何网络请求,也不写入浏览器存储,刷新即恢复默认示例。

相关工具