🎭 故事开场:深夜加班,小明盯着屏幕上的嵌套 JSON 发呆:
data.user.profile.settings.theme... 写结构体?太麻烦!用map[string]interface{}?类型断言写到崩溃!直到他遇见了 gjson——"原来解析 JSON 可以这么优雅!"
✨ gjson 是什么?
一句话:不用定义结构体,不用层层断言,一行代码提取任意嵌套的 JSON 值。
go get -u github.com/tidwall/gjson
🎯 核心用法:点语法,像查字典一样简单
import "github.com/tidwall/gjson"
const json = `{"user":{"name":"小红","age":18},"tags":["Go","Rust"]}`
// 取值?就这么简单!
name := gjson.Get(json, "user.name").String() // "小红"
age := gjson.Get(json, "user.age").Int() // 18
firstTag := gjson.Get(json, "tags.0").String() // "Go"
💡 路径语法速查:
.访问嵌套字段:user.name#数组长度或遍历:tags.#→ 2*/?通配符:user.n?me→ 匹配 name#(...)条件查询:friends.#(age>20).name
🔥 实战场景:3 个让你"哇塞"的例子
🎁 场景1:批量提取数组字段
// JSON: {"users":[{"name":"A"},{"name":"B"}]}
names := gjson.Get(json, "users.#.name").Array()
for _, n := range names {
println(n.String()) // 输出: A, B
}
🎯 场景2:条件过滤,精准打击
// 找第一个年龄>25且姓氏为"张"的用户
result := gjson.Get(json, `users.#(age>25)#(last=="张").first`)
if result.Exists() {
println("找到啦:", result.String())
}
⚡ 场景3:链式修饰,花式处理
// 反转数组 + 取第一个 + 转大写
val := gjson.Get(json, "tags|@reverse|0|@tostr")
// 原: ["Go","Rust"] → 反转: ["Rust","Go"] → 取0: "Rust" → 转字符串
💡 我的使用心得(避坑指南)
- 性能怪兽:基准测试显示
gjson.Get约 200ns/次,零内存分配,高并发场景放心用 - 别忘校验:外部传入的 JSON 先用
gjson.Valid(json)检查,避免意外 - Bytes 优先:处理
[]byte时用GetBytes,避免不必要的 string 转换 - 存在性判断:
result.Exists()比result.String() != ""更可靠(空字符串也是合法值!)
// ✅ 推荐写法
if val := gjson.Get(json, "optional.field"); val.Exists() {
process(val.String())
}
🎁 彩蛋:自定义 Modifier,解锁隐藏技能
// 添加一个 "upper" 修饰符,把结果转大写
gjson.AddModifier("upper", func(json, arg string) string {
return strings.ToUpper(json)
})
// 使用:把用户名转大写
name := gjson.Get(json, "user.name|@upper").String() // "小红" → "小红" (中文无影响,英文爽翻)