gjson.Get比json.Unmarshal快得多,因其不解析整个JSON、不走反射、不构建Go值,仅在字节流上按路径扫描并切片返回原始片段,零分配、无类型转换、不递归。

gjson 不是用来“学习语言”的,它是为生产环境里快速提取 JSON 字段而生的——别拿它当 Go 入门教材,也别指望它帮你理解结构体或反射原理。
gjson.Get 为什么比 json.Unmarshal 快得多
根本原因在于:它不解析整个 JSON,只按路径扫描字节流,找到目标值就停。没有反射、不构造 struct、不分配 map 或 slice。
-
json.Unmarshal必须把整个 JSON 映射成 Go 类型,哪怕你只想要"user.id",也要遍历所有字段、做类型推断、分配内存 -
gjson.Get直接在[]byte上游走,用状态机跳过无关内容,平均耗时约200ns,且零堆分配 - 当你反复调用
gjson.Get解析同一段 JSON,性能不会衰减;但json.Unmarshal每次都重新解析、重新分配
字符串 vs []byte:别让 string 转换拖慢 gjson
Go 中 string 是只读的,[]byte 可修改。gjson 内部直接操作字节,所以传 []byte 比传 string 少一次底层拷贝。
- 用
gjson.GetBytes(data, "path")替代gjson.Get(string(data), "path") - 如果你的数据源本来就是
[]byte(比如 HTTP body、文件读取结果),直接传进去,别转string - 如果必须从
string开始,且高频调用,考虑提前转成[]byte缓存,避免重复转换
Exists() 和 String() 的语义差异常被忽略
result.String() 返回空字符串 "" 有两种可能:字段不存在,或字段值本身就是 ""。而 result.Exists() 才真正告诉你“这个路径有没有被找到”。
立即学习“go语言免费学习笔记(深入)”;
- 判断字段是否存在,请用
gjson.Get(json, "user.email").Exists(),而不是gjson.Get(json, "user.email").String() != "" - 获取数值时,优先用
result.Int()或result.Float(),它们对非数字类型返回 0,但不会 panic;result.String()对 null 或 number 也能返回可读字符串,但语义模糊 - 数组长度查询用
gjson.Get(json, "items.#"),返回的是int64,不是字符串
嵌套数组 + 条件过滤:路径写错就查不到
gjson 的路径语法看着像 JS,但行为更严格。通配符和条件查询容易写错,尤其当 JSON 结构动态时。
-
friends.#(age>30).name匹配第一个 age > 30 的 friend 的 name;friends.#(age>30)#.name才返回所有匹配项的 name 数组 - 字段名含点号(如
"fav.movie")必须用反斜杠转义:"fav\.movie",否则会被当成嵌套路径 - 数组索引从 0 开始,
items.0是第一个,items.-1不支持,不能用负数索引 - 路径中空格、特殊字符未被转义会导致匹配失败,建议用
gjson.Valid(json)先校验再查
真正难的不是写对一行 gjson.Get,而是当 JSON schema 变动、字段缺失、类型混杂时,还能让 Exists()、Int()、Array() 这些方法返回符合预期的结果——这需要你始终带着“JSON 是外部输入”的警惕去写逻辑,而不是当成内部可控数据来信任。



















