gjson.get比json.unmarshal快5–10倍,因其不解析整个json、不构造go值、不走反射,仅在字节流上按路径扫描并切片返回原始片段,零分配、无类型转换、不递归,且对缺失字段天然容错。

直接用 gjson.Get,别先 json.Unmarshal 再层层断言——动态 JSON 路径提取场景下,它快 5–10 倍,且不会 panic。
为什么 gjson.Get 比 json.Unmarshal + map[string]interface{} 快得多
因为 gjson.Get 不解析整个 JSON 字符串,不构造 Go 值,也不走反射。它只在字节流上按路径扫描,找到匹配位置后切片返回原始数据片段。零分配、无类型转换、不递归。
-
json.Unmarshal必须完整解析并构建嵌套map[string]interface{}和[]interface{},每层都要做类型断言和空值检查 -
gjson.Get对缺失字段天然容错:路径不存在时.Exists()返回false,而不是 panic - 数字字段(如
"id": 123)在gjson.Result中仍保持原始格式,调.Int()或.String()才做转换,避免标准库默认全转float64的陷阱
如何安全提取嵌套数组中的动态字段(比如 items.0.name 或 items.-1.id)
路径支持点号 + 索引,但必须注意索引越界不会报错,而是返回空 gjson.Result;所以不能只靠 .String() 判断,得先 .Exists()。
-
gjson.Get(jsonStr, "items.0.name")→ 取第一个 item 的 name -
gjson.Get(jsonStr, "items.-1.id")→ 取最后一个 item 的 id(-1是合法索引) -
gjson.Get(jsonStr, "items.#")→ 返回数组长度(.Int()可取值) - 若不确定数组是否存在,务必写成:
if res := gjson.Get(jsonStr, "items.0.url"); res.Exists() { url := res.String() }
遇到 key 名动态变化时(如 "200x300", "50x100")怎么处理
gjson 本身不支持正则或模糊匹配 key,但它能快速定位父对象,再用原生 Go 遍历子 map —— 这才是轻量又可控的做法。
- 先用
gjson.Get(jsonStr, "image_urls")拿到整个 object 结果 - 检查是否为 object:
if res.IsObject() { ... } - 转成 map:
m := res.Map(),返回的是map[string]gjson.Result,不是map[string]interface{} - 遍历 keys:
for k, v := range m { url := v.String() },无需任何类型断言
容易被忽略的性能与兼容性细节
很多人用 gjson.Get 但没意识到:传 string 会隐式转 []byte,而 gjson.GetBytes 直接操作字节切片,少一次内存拷贝;另外,外部不可信 JSON 必须先 gjson.Valid() 校验,否则路径扫描可能越界读内存。
- 高频场景优先用
gjson.GetBytes(data, path),尤其当data已是[]byte -
.String()总是返回新分配的字符串,若只需比较或判断存在,用.Exists()或.Equal()更省 -
gjson.Get不保证 UTF-8 安全——如果原始 JSON 含非法编码,.String()可能返回乱码,但不会 panic
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











