promoted Unmarshal method on embedded field caused confusion 后续
hantmac · · 815 次点击 · · 开始浏览encoding/json: promoted Unmarshal method on embedded field caused confusion
接上一篇,官方在早上给了回复:
简单解释下就是嵌入字段 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, 这位大佬给出的方案和代码还是很赏心悦目的,值得学习(抄一下)。
------------------------------ END ----------------------------------
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
encoding/json: promoted Unmarshal method on embedded field caused confusion
接上一篇,官方在早上给了回复:
简单解释下就是嵌入字段 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, 这位大佬给出的方案和代码还是很赏心悦目的,值得学习(抄一下)。
------------------------------ END ----------------------------------