前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang json自定义解析

golang json自定义解析

作者头像
公众号guangcity
发布2021-10-12 11:47:06
2.7K0
发布2021-10-12 11:47:06
举报
文章被收录于专栏:光城(guangcity)

golang json自定义解析

1.使用背景

假设json格式为:

代码语言:javascript
复制
{
 "op": "+",
 "num1": 10,
 "num2": 13
}

最终需要转换为:

代码语言:javascript
复制
{
 "op": "+",
 "result": 23
}

此时,golang的json的序列化是否支持呢?

2.自定义解析

golang encoding/json中支持用户自定义json序列化,只需要实现当前结构体的UnmarshalJSON/MarshalJSON。

例如:上述例子,这里以UnmarshalJSON为例。

代码语言:javascript
复制
// UnmarshalJSON
func (o *Operation) UnmarshalJSON(data []byte) error {
 // type 定义新类型  避免内部循环引用 导致stack overflow
 type opShadow Operation
 var tmp opShadow
 if err := json.Unmarshal([]byte(data), &tmp); err != nil {
  return err
 }
 switch tmp.Op {
 case "+":
  o.Result = tmp.Num1 + tmp.Num2
 case "-":
  o.Result = tmp.Num1 - tmp.Num2
 }
 o.Op = tmp.Op
 return nil
}

实际上就是在方法中实现自己的业务逻辑,注意内部使用了Unmarshal,会导致鸡生蛋,蛋生鸡的问题,谁依赖谁,一直死循环依赖,最终导致stack overflow,因此在内部需要type一个类型,用这个别名类型来操作。

3.使用编译时断言

在上述使用代码中,我们添加:

代码语言:javascript
复制
var _ json.Unmarshaler = (*Operation)(nil

便可以在编译时看到自己写的UnmarshalJSON接口是否正确,如果没写/不正确,此时会报错,非常好用。

在c++中我们也是秉持编译时优先抛出问题,golang也是如此,使用编译时的断言简单好用,还可以避免一些错误问题。

4.嵌入式结构体

针对嵌入式结构体的UnmarshalJSON使用,我们往往会出错,例如:

代码语言:javascript
复制
var testJSON = `{"num":5,"duration":"5s"}`

type Nested struct {
 Dur time.Duration `json:"duration"`
}

func (n *Nested) UnmarshalJSON(data []byte) error {
 *n = Nested{}
 tmp := struct {
  Dur string `json:"duration"`
 }{}
 fmt.Printf("parsing nested json %s \n", string(data))
 if err := json.Unmarshal(data, &tmp); err != nil {
  fmt.Printf("failed to parse nested: %v", err)
  return err
 }
 tmpDur, err := time.ParseDuration(tmp.Dur)
 if err != nil {
  fmt.Printf("failed to parse duration: %v", err)
  return err
 }
 (*n).Dur = tmpDur
 return nil
}

type Object struct {
 Nested
 Num int `json:"num"`
}
func (o *Object) UnmarshalJSON(data []byte) error {
 *o = Object{}
 tmp := struct {
  Nested
  Num int `json:"num"`
 }{}
 fmt.Printf("parsing object json %s \n", string(data))
 if err := json.Unmarshal(data, &tmp); err != nil {
  fmt.Printf("failed to parse object: %v", err)
  return err
 }
 fmt.Printf("tmp object: %+v \n", tmp)
 (*o).Num = tmp.Num
 (*o).Nested = tmp.Nested
 return nil
}

在这段代码中,我们最终想要做的是Unmarshal为Object,那么会调用UnmarshalJSON,在这个方法中,调用了Unmarshal,此时会去调用Nested的UnmarshalJSON,便会导致num解析不出来,为了解决这种问题,我们可以做两次解析,也就是潜入类型与本身成员拆分。

代码语言:javascript
复制
tmp := struct {
  //Nested
  Num int `json:"num"`

}{}
// unmarshal Nested alone
tmpNest := struct {
  Nested
}{}
fmt.Printf("parsing object json %s \n", string(data))
if err := json.Unmarshal(data, &tmp); err != nil {
  fmt.Printf("failed to parse object: %v", err)
  return err
}
// the Nested impl UnmarshalJSON, so it should be unmarshaled alone
if err := json.Unmarshal(data, &tmpNest); err != nil {
  fmt.Printf("failed to parse object: %v", err)
  return err
}

至此,便可以解决嵌入类型Unmarshal的问题。

本节完

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • golang json自定义解析
    • 1.使用背景
      • 2.自定义解析
        • 3.使用编译时断言
          • 4.嵌入式结构体
          相关产品与服务
          文件存储
          文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档