encoding/json: promoted Unmarshal method on embedded field caused confusionweb
接上一篇,官方在早上给了回复:json
简单解释下就是嵌入字段 Nested
的方法被提高了,致使 Object
的方法不会被执行,因此 Num
字段不会被 Unmarshal
。跟上一篇中的解释差很少意思。可是官方给了两种更加优雅的解决这个问题的方式,让咱们来欣赏下大佬的代码。编辑器
代码中只需添加下面一行便可:ide
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
。学习
实现 custom time unmarshaller
。ui
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
接口。我的倾向于第一种添加类型断言的方式,简洁又容易理解 ,对代码侵入比较小。url
官方对这个问题的回复仍是很热情的,他说他本身的团队在几年前也遇到了如出一辙的问题,很能理解开发者的心情,他当时还针对这个问题写了一篇相似的文章,https://medium.com/@odeke_et/compile-type-assertions-to-the-rescue-6ddab4b8398b。我说啥来着,这是一个前人踩坑,后人踩坑,将来还会踩的坑。spa
u1s1, 这位大佬给出的方案和代码仍是很赏心悦目的,值得学习(抄一下)。code
------------------------------ END ----------------------------------cdn