【golang】3、序列化、json、jsoniter

在这里插入图片描述

一、序列化

我们经常需要把 Json Object 反序列化到 struct,然而官方库总有各种限制。

为了灵活我们可以用 json.Marshaler 实现,但他增加了复杂性(要写很多代码)、而且要避免申请太多内存。

参考鸟窝
参考jsonter作者

1.1 用 *time.Time 避免序列化得到null

数据库的 create_time、update_time 通常建议用 *time.Time 类型,而不用 time.Time 类型

值方式:

func main() {
	type tm struct {
		T1 time.Time
		T2 time.Time
	}
	now := time.Now()
	t := &tm{
		T1: now,
	}
	s, _ := json.Marshal(t)
	print(string(s))
	signal.WaitForExit()
}

// 结果如下:
{"T1":"2022-10-11T17:15:10.11307+08:00","T2":null} // 这样通常前端可以解析,因为js的也有null的类型

指针方式:

func main() {
	type tm struct {
		T1 *time.Time
		T2 *time.Time
	}
	now := time.Now()
	t := &tm{
		T1: &now,
	}
	s, _ := json.Marshal(t)
	print(string(s))
	signal.WaitForExit()
}

// 结果如下:
{"T1":"2022-10-11T17:15:10.11307+08:00","T2":"0001-01-01T00:00:00Z"} // 这样通常如果希望前端 hard code 用 "0001-01-01T00:00:00Z" 来判断是够为空时间,就太苟了

1.2 jsoniter 字符串和数字互转

golang 的 jsoniter 容忍字符串和数字互为转换,通常用雪花算法做数据库的主键,但前端的 js 语言层面的 Number 类型无法解析(雪花算法的 id 超出了 number 类型的值域),这就造成了矛盾:前端 js 只能用 String 解析,而后端需要用 BigInt 存数据库。

为了解决此问题,前端和数据库之间的 web后端,需要对 golang 的 string 和 int64 做转换,可通过 jsoniter 库实现此功能,就是在属性添加 json:",string" 的标签即可,代码如下:

class model struct {
	ID int64 `json:",string"`
	Name string `json:"name"`
}

1.3 json 只解析需要的字段

json 解析,会只解析需要的字段。例如下例 struct S 只有 2个字段,b1 有2个字段,而 b2 有3个字段,但 b1 和 b2 都可以 Unmarshal 成功:

package main

import (
	"github.com/datager/codes/gocodes/dg/utils/json"
	"github.com/datager/codes/gocodes/dg/utils/signal"
)

type S struct {
	A string
	B int64
}

func main() {
	b1 := `{"A":"1", "B":2}`
	b2 := `{"A":"1", "B":2, "C": 3}`
	v1 := &S{}
	v2 := &S{}
	if err := json.Unmarshal([]byte(b1), v1); err != nil {
		panic(err)
	}
	if err := json.Unmarshal([]byte(b2), v2); err != nil {
		panic(err)
	}
	signal.WaitForExit()
}

二、merge 两个 json

Go语言中合并两个JSON对象的一种常用方法是:将它们都解码为Go语言的map[string]interface{}类型,然后遍历后一个map并将它的每个键/值对添加到前一个map中。

最终,合并后的JSON字节数组将被返回。如果在解码或编码过程中出现错误,则返回相应的错误。

参考

// base from bx, merge by to it
// if exist same key, overwrite value
// if not exist same key, add new value
func mergeJSON(bx, by []byte) ([]byte, error) {
	mx, my := make(map[string]any), make(map[string]any)
	if err := json.Unmarshal(bx, &mx); err != nil {
		return nil, err
	}
	if err := json.Unmarshal(by, &my); err != nil {
		return nil, err
	}
	for k, v := range my {
		mx[k] = v
	}
	return json.MarshalIndent(mx, "", "\t")
}

三、常见库

3.1 gjson、sjson

sjson.Set(str, k, v)
v := gjson.Get(str, k)

3.2 viper

viper 为了支持环境变量,内部全部使用小写风格,使得生成的 json 文件也是小写风格的,容易造成不兼容。(虽然 viper 读取、使用、写入都是不区分大小写的)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值