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爱好者值得关注


浏览 16
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报