golang之json.RawMessage
RawMessage 具体来讲是 json 库中定义的一个类型。它实现了 Marshaler 接口以及 Unmarshaler 接口,以此来支持序列化的能力。注意上面我们引用 官方 doc 的说明。
使用场景
设想一下,我们给某种业务场景定义了一个通用的 model,其中部分数据需要在不同场景下对应不同的结构体。这个时候怎么 Marshal 成字节数组,存入数据库,以及读出数据,还原出 model 呢?
我们就可以将这个可变的字段定义为 json.RawMessage,利用它适配万物的能力来进行读写。
复用预计算的 json 值
package main import (
"encoding/json"
"fmt"
"os"
) func main() {
h := json.RawMessage(`{"precomputed": true}`) c := struct {
Header *json.RawMessage `json:"header"`
Body string `json:"body"`
}{Header: &h, Body: "Hello Gophers!"} b, err := json.MarshalIndent(&c, "", "\t")
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b) }
输出:
{
"header": {
"precomputed": true
},
"body": "Hello Gophers!"
}
这里 "precomputed": true 跟我们构造的 RawMessage 是一模一样的,所以对应到第一个能力:在序列化时使用一个预先计算好的 json 值。
延迟解析 json 结构
package main import (
"encoding/json"
"fmt"
"log"
) func main() {
type Color struct {
Space string
Point json.RawMessage // delay parsing until we know the color space
}
type RGB struct {
R uint8
G uint8
B uint8
}
type YCbCr struct {
Y uint8
Cb int8
Cr int8
} var j = []byte(`[
{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
{"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255}}
]`)
var colors []Color
err := json.Unmarshal(j, &colors)
if err != nil {
log.Fatalln("error:", err)
} for _, c := range colors {
var dst any
switch c.Space {
case "RGB":
dst = new(RGB)
case "YCbCr":
dst = new(YCbCr)
}
err := json.Unmarshal(c.Point, dst)
if err != nil {
log.Fatalln("error:", err)
}
fmt.Println(c.Space, dst)
}
}
这里的例子其实更典型。Color 中的 Point 可能存在两种结构描述,一种是 RGB,另一种是 YCbCr,而我们对应到底层存储,又希望能复用,这是非常常见的。
所以,这里采用了【两级反序列化】的策略:
- 第一级,解析出来公共字段,利用 json.RawMessage 延迟这部分差异字段的解析。
- 第二级,根据已经解析出来的字段(一般是有类似 type 的语义),判断再次反序列化时要使用的结构,基于 json.RawMessage 再次 Unmarshal,拿到最终的数据。
上面的示例输出结果如下:
YCbCr &{255 0 -10}
RGB &{98 218 255}
使用示例:
1)如果json串没有固定的格式导致不好定义与其相对应的结构体时,我们可以使用json.RawMessage原始字节数据保存下来 ,然后一层一层的进行解析:
type sendMsg struct {
Name string `json:"name"`
Info string `json:"info"`
}
func jsonTest() {
jsonStr := `{"sendMsg":{"name":"louiswang","info":"这里是一条消息"},"say":"Hello"}`
var data map[string]json.RawMessage
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
fmt.Println("json 解析失败了:", err)
return
}
var saystr string
if err := json.Unmarshal(data["say"], &saystr); err != nil {
fmt.Println("RawMessage 解析失败了:", err)
return
}
fmt.Printf("%#v-------%T\n", saystr, saystr)
var resMsg sendMsg
if err := json.Unmarshal(data["sendMsg"], &resMsg); err != nil {
fmt.Println("RawMessage 解析失败了(sendMsg):", err)
return
}
fmt.Printf("%#v-----%T\n", resMsg, resMsg)
fmt.Println(resMsg.Name, resMsg.Info)
}
总结
json 提供的 RawMessage 是直接暴露了底层的 []byte 作为交互凭证,它可以被内嵌在各种结构体中。作为不可变的字段类型的 placeholder,延迟解析。相较于 string 类型效率更高。从实现上看非常简单,只是封装了一层字节数组的交互,大家可以放心使用。
golang之json.RawMessage的更多相关文章
- Golang 处理 Json(二):解码
golang 编码 json 还比较简单,而解析 json 则非常蛋疼.不像 PHP 一句 json_decode() 就能搞定.之前项目开发中,为了兼容不同客户端的需求,请求的 content-ty ...
- 48 【golang】json的效率
本文将主要做如下几方面的测试: 1,构造一个[100]struct的数组,然后来测试它的json编码后的字符串 或者([]byte),首先关心它的功能是否正常: 2,在很早之前,我们在使用golang ...
- Go_14:GoLang中 json、map、struct 之间的相互转化
1. golang 中 json 转 struct <1. 使用 json.Unmarshal 时,结构体的每一项必须是导出项(import field).也就是说结构体的 key 对应的首字母 ...
- Golang 处理 Json(一):编码
JSON 是一种数据格式描述语言.以 key 和 value 构成的哈系结构,类似 Javascript 中的对象,python 中的字典.通常 json 格式的 key 是字符串,其值可以是任意类型 ...
- GoLang中 json、map、struct 之间的相互转化
1. golang 中 json 转 struct <1. 使用 json.Unmarshal 时,结构体的每一项必须是导出项(import field).也就是说结构体的 key 对应的首字母 ...
- golang解析json报错:invalid character '\x00' after top-level value
golang解析json报错:invalid character '\x00' after top-level value 手动复制字符串:{"files":["c:/t ...
- Golang - 处理json
目录 Golang - 处理json 1. 编码json 2. 解码json Golang - 处理json 1. 编码json 使用json.Marshal()函数可以对一组数据进行JSON格式的编 ...
- golang webservice[ json Martini webframe]
golang webservice[ json Martini webframe] https://github.com/brunoga/go-webservice-sample 自己修改了一下例子, ...
- Golang的json包
encoding/json encoding/json是官方提供的标准json, 实现RFC 7159中定义的JSON编码和解码.使用的时候需要预定义struct,原理是通过reflection和in ...
- Golang解析json的几种方法
Golang解析json的几种方法 概要 使用Golang调用其它平台API接口时总会被多层的json串给恶心到,我记录一下自己解析json的几种方法. 一.自带的json包 func JsonUnm ...
随机推荐
- Falcon Mamba: 首个高效的无注意力机制 7B 模型
Falcon Mamba 是由阿布扎比的 Technology Innovation Institute (TII) 开发并基于 TII Falcon Mamba 7B License 1.0 的开放 ...
- windows系统使用UnblockNeteaseMusic解锁网易云音乐灰色歌曲
使用UnblockNeteaseMusic解锁网易云音乐灰色歌曲 一.问题 用网易云音乐听歌曲,有的曲目听不了,如下: 二.解决步骤 参照:https://github.com/nondanee/Un ...
- SPIE独立出版。遥感征稿中--2024年遥感与数字地球国际学术会议(RSDE 2024)
[成都,遥感主题,稳定EI检索]2024年遥感与数字地球国际学术会议(RSDE 2024) 2024 International Conference on Remote Sensing and ...
- 2019牛客暑期多校训练营(第四场)J-free(分层图最短路)
>传送门< 题意:给你n个城市,m条道路,经过每一条要花费这条路的代价,现给你k个机会,使得最多k条路的代价为0,问从起点s到终点t花费的最少代价 思路:分层图最短路经典裸题 方法一 Co ...
- ++i与i++在效率上的细微差别
在一些特定的使用中, i++ 可能将原值用中间量存起来以待使用,下面看相关程序的汇编代码(使用 gcc ). i++ 源程序: #include <stdio.h> int main(){ ...
- 信创环境经典版SuerMap iManager ARM版部署流程
一.环境 操作系统:银河麒麟kylin V10 CPU:鲲鹏920 SuperMap iManager 10.2.1 硬件:4H32G机器 磁盘分区格式建议如下(请严格按照如下,减少后期有用/目录资源 ...
- 命令行gcc -v和g++ -v输出版本不一致
命令行gcc -v和g++ -v输出版本不一致 前言:本文初编辑于2024年1月30日 CSDN主页:https://blog.csdn.net/rvdgdsva 博客园主页:https://www. ...
- docker 安装 elasticsearch 集群
此处部署为单个服务器启动三个elasticsearch容器 问题:本打算在三个服务器上单独部署elasticsearch 容器,elasticsearch.yml 注册用的宿主机ip,但是容器之间通信 ...
- USB Type-C Power Role
USB Power Role 是指 USB 设备在供电方面所扮演的角色,主要分为供电方(Provider)和受电方(Consumer).在 USB 供电协议中,电源角色的管理尤为重要,尤其是在 USB ...
- KPTI——可以缓解“熔断” (Meltdown) 漏洞的内核新特性
Linux 内核修复办法:内核页表隔离KPTl(kernel page table isolation) 每个进程一张页表变成两张:运行在内核态和运行在用户态时分别使用各自分离的页表 Kernel页表 ...