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}
总结
json 提供的 RawMessage 是直接暴露了底层的 []byte 作为交互凭证,它可以被内嵌在各种结构体中。作为不可变的字段类型的 placeholder,延迟解析。相较于 string 类型效率更高。从实现上看非常简单,只是封装了一层字节数组的交互,大家可以放心使用。
标签:YCbCr,err,Space,RGB,RawMessage,golang,json From: https://www.cnblogs.com/xingxia/p/18159806/golang_json_rawMessage