首页 > 其他分享 >golang之json.RawMessage

golang之json.RawMessage

时间:2024-04-26 12:55:33浏览次数:28  
标签:YCbCr err Space RGB RawMessage golang json

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

相关文章

  • Golang - 空指针如何预防
    在Go语言中,空指针是一个常见的运行时错误来源,它通常发生在尝试访问一个未被初始化或已被设置为nil的指针所指向的值。1、凡是有点『.』操作的的行为都要先进行非nil判断:例如,想记录一个err的msg,通过err.Error()就可以获取到err的string类型的错误消息msg,但这里需要对err进行非nil......
  • Javascript的数据类型和json数组
    4个数据类型:NumberStringBooleanUndefinedalert(parseInt(k));//如果不是数字会输出NaN,从第一个字符开始输出数字,直到不是数字后返回值。json数组://js中k、v型数据,使用jsonvarperson={name:"张三",//注意里面的元素用,分割。定义的是key是name的value值为张三age......
  • JSON 序列化 属性名 大写变成小写 保持不变 newsoft.json system.text.json
    JSON序列化属性名由大写变成小写的问题在ASP.NET中,默认情况下,JSON序列化会将属性名转换为小写(camelcase)以匹配JSON的约定。如果您希望保留C#的命名约定(即属性名的大小写不变),您需要更改默认的JSON序列化器。System.Text.Json使用System.Text.Json(推荐):在Startup.c......
  • lazarus数据序列为JSON
    uses  DataSet.Serialize, fpjson;varobj:tjsonobject;procedureTForm1.Button1Click(Sender:TObject);beginuniquery1.Close;uniquery1.SQL.clear;uniquery1.sql.Add('selecttop2*fromtunit');uniquery1.Open;memo1.text:=uniquery1......
  • 【2024最新】获取街道、镇级的地图geoJson数据方法
    一、目的1、在echarts上绘制市级以下的区、县的区域地图。2、在市级下很多都是有区、县的区域,而少部分是不存在区、县的,是直接市下面一级就是街道、镇级别的区域。3、统一管理区域数据,有区县的市直接拿区县的geoJson数据,没有区县的市级直接拿街道、镇级的geoJson数据来绘制区......
  • golang工具函数,把一个金额整型,单位为分,转成"1,231,111.00"格式的字符串
    这个函数首先将整数除以100来获取代表元的浮点数,然后格式化此数值为两位小数的字符串。接下来,函数将字符串分成整数和小数部分,并且为整数部分添加千位分隔符。最后,如果存在小数部分,它会将这两部分重新组合并返回正确格式化的金额字符串。为了正确地处理负数,我们需要先检查金额是......
  • Python基础-模块和包(hashlib、random、json、time、datetime和os模块)
    什么是模块和包?模块:python中的.py文件,将一些功能按照某一种维度进行划分;自定义、内置。、第三方.包:文件夹里面好多个.py文件。在讨论的时候,一般统称为:模块。学习:自定义模块和包+使用内置模块+使用第三方模块+使用1自定义模块和包1.1快速上手-项目文件夹(......
  • Golang - 并发同步更新全局切片失败的原因以及解决方案
    当多个协程同时访问和修改同一个共享资源(如切片)时,如果没有适当的同步机制,可能会导致数据竞争和不一致的结果。packagemainimport("fmt""sync")funcprocessChunk(chunk[]int64,wg*sync.WaitGroup,failedList[]int64){deferwg.Done()fmt.Print......
  • golang 实现文件下载
    golang实现文件下载packagemainimport("fmt""html/template""io""io/fs""mime""net/http""os""path/filepath""regexp"&qu......
  • 银行卡归属地查询JSON
    [{"bankName":"中国邮政储蓄银行","bankCode":"PSBC","patterns":[{"reg":"^(621096|621098|622150|622151|622181|622188|622199|955100|6210......