JSON 的填坑之旅:官方给的解答

共 2260字,需浏览 5分钟

 ·

2020-08-26 13:09

encoding/json: promoted Unmarshal method on embedded field caused confusion

接上一篇: golang 使用 UnmarshalJSON 接口实现自定义 unmarshal 的坑,官方给的回复:

简单解释下就是嵌入字段 Nested 的方法被提升了,导致 Object 的方法不会被执行,所以 Num 字段不会被 Unmarshal。跟上一篇中的解释差不多意思。但是官方给了两种更加优雅的解决这个问题的方式,让我们来欣赏下大佬的代码。

方法 a

代码中只需添加下面一行即可:

var _ json.Unmarshaler = (*Object)(nil)
package main

import (
 "encoding/json"
 "fmt"
 "time"
)

var testJSON = `{"num":5,"duration":"5s"}`

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

func (obj *Object) UnmarshalJSON(data []byte) error {
 tmp := struct {
  Dur string `json:"duration"`
  Num int    `json:"num"`
 }{}
 if err := json.Unmarshal(data, &tmp); err != nil {
  return err
 }

 dur, err := time.ParseDuration(tmp.Dur)
 if err != nil {
  return err
 }
 obj.Dur = dur
 obj.Num = tmp.Num
 return nil
}

type Object struct {
 Nested
 Num int `json:"num"`
}

var _ json.Unmarshaler = (*Object)(nil)

func main() {
 obj := Object{}
 _ = json.Unmarshal([]byte(testJSON), &obj)
 fmt.Printf("result: %+v \n", obj)
}

随后这位老哥补充到,在嵌入字段都实现了接口方法的情况下,The type assertion will be a nice guide, 添加该类型的断言是一个好的实践,可以帮助你快速捕捉到潜在的 bug

方法 b

实现 custom time unmarshaller

package main

import (
 "encoding/json"
 "fmt"
 "time"
)

var testJSON = `{"num":5,"duration":"5s"}`

type customTimeDuration time.Duration

type Nested struct {
 Dur customTimeDuration `json:"duration"`
}

func (ctd *customTimeDuration) UnmarshalJSON(b []byte) error {
 var durStr string
 if err := json.Unmarshal(b, &durStr); err != nil {
  return err
 }
 dur, err := time.ParseDuration(durStr)
 if err == nil {
  *ctd = customTimeDuration(dur)
 }
 return err
}

type Object struct {
 Nested
 Num int `json:"num"`
}

func main() {
 obj := Object{}
 _ = json.Unmarshal([]byte(testJSON), &obj)
 fmt.Printf("result: %+v \n", obj)
}

这种方式其实就是跟以上一篇分开解析的思路比较像,他重新声明了别名类型,然后为这个别名类型实现 UnmarshalJson 接口。个人倾向于第一种添加类型断言的方式,简洁又容易理解 ,对代码侵入比较小。

官方对这个问题的回复还是很热情的,他说他自己的团队在几年前也遇到了一模一样的问题,很能理解开发者的心情,他当时还针对这个问题写了一篇类似的文章,https://medium.com/@odeke_et/compile-type-assertions-to-the-rescue-6ddab4b8398b。我说啥来着,这是一个前人踩坑,后人踩坑,未来还会踩的坑。

u1s1, 这位大佬给出的方案和代码还是很赏心悦目的,值得学习(抄一下)。




推荐阅读



学习交流 Go 语言,扫码回复「进群」即可


站长 polarisxu

自己的原创文章

不限于 Go 技术

职场和创业经验


Go语言中文网

每天为你

分享 Go 知识

Go爱好者值得关注


浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐