
文章目录tidwall/sjsonGo 里改 JSON点号路径就够了1、一行改一个值2、改、删、追加一个库覆盖3、性能不反序列化整棵树4、类型支持和回退机制5、作者和配套工具6、适合这些场景tidwall/sjsonGo 里改 JSON点号路径就够了tidwall/sjson 在 GitHub 上拿到了 2,709 Star。Go 里处理 JSON 改值标准库的路径是定义 struct、json.Unmarshal、修改字段、json.Marshal 回去。就想把name.last从 “Prichard” 改成 “Anderson”四步起跳。改一次可以忍但日志管道、API 网关这种每秒改几百次的场景序列化和反序列化的开销堆起来之后就是另一回事了。SJSON 做一件事用一段点号路径定位到想改的位置只动那一段字节其余内容原样保留。1、一行改一个值使用方式没有多余的步骤value,_:sjson.Set(json,name.last,Anderson)输入{name:{first:Janet,last:Prichard},age:47}输出{name:{first:Janet,last:Anderson},age:47}。不需要定义 struct不需要 Unmarshal不需要 Marshal。路径指向哪里就改哪里。路径语法是点号分隔的 keyname.last进入嵌套对象的字段children.1取数组下标 1 的元素friends.1.last取数组元素下的嵌套字段key 本身含 “.” 的情况用\转义。如果 JSON 里用数字作为对象 key比如{users:{2313:{name:Sara}}}路径写成users.:2313.name加冒号区分数组索引和对象 key。2、改、删、追加一个库覆盖Delete 操作同样简洁sjson.Delete(json,name.first)数组末尾追加用-1作为 keysjson.Set(json,friends.-1,Sara)即使在数组边界之外指定索引数组 2 个元素却在friends.4位置设值SJSON 自动补 null 填满中间位置不会 panic。3、性能不反序列化整棵树作者给出的 benchmark同一段 JSON 文档上轮流操作三个不同路径结果如下方法耗时内存分配SJSON Set805 ns/op1077 B/op, 3 allocsSJSON ReplaceInPlace449 ns/op0 B/op, 0 allocsencoding/json (Map)21236 ns/op6392 B/op, 150 allocsEasyJSON3119 ns/op1061 B/op, 13 allocsSJSON 的 Set 比标准库快约 26 倍ReplaceInPlace 模式零分配差距拉到 47 倍。原理直接在字节层面操作定位目标字段对应的起止字节位置替换中间内容。没有 reflect没有中间对象分配。ReplaceInPlace 模式下如果新旧值字节长度相同直接原地覆盖一次分配都没有。对高并发 API 网关、日志处理管线、配置中心这类场景省下的不只是响应时间还有 GC 开销。4、类型支持和回退机制原生支持 nil、bool、int、float、string、slice、map。如果传入的类型不在这个范围SJSON 自动回退到encoding/json的 Marshaller 处理后再拼接。自定义 struct 照常往里塞不需要额外适配。5、作者和配套工具SJSON 的作者是 Josh Bakertidwall。他在 Go 社区还有几个关联项目GJSON做 JSON 快速查询路径语法和 SJSON 一致Star 数比 SJSON 更高JJ把 GJSON 加 SJSON 包装成命令行工具shell 里直接查改 JSON想从 JSON 里取某个值用 GJSON想往 JSON 里改某个值用 SJSON语法一样配合起来没有学习成本。6、适合这些场景配置中心或 API 网关需要高频修改 JSON 响应中的个别字段日志处理管线在全量解析之外提供增删字段的能力JSON 结构不固定不适合提前定义 struct和 GJSON 搭配一读一写覆盖多数 JSON 操作如果每次都要完整理解 JSON 全貌才能决定改什么SJSON 帮不上忙。但如果修改路径是已知的、只动一个值它能省下很大的 CPU 和内存开销。不上忙。但如果修改路径是已知的、只动一个值它能省下很大的 CPU 和内存开销。[外链图片转存中…(img-22wNkboi-1780899443454)]