嵌入式结构的多态 JSON 解组
Posted
技术标签:
【中文标题】嵌入式结构的多态 JSON 解组【英文标题】:Polymorphic JSON unmarshalling of embedded structs 【发布时间】:2017-06-06 01:34:39 【问题描述】:这是一个例子(另见https://play.golang.org/p/or7z4Xc8tN):
package main
import (
"encoding/json"
"fmt"
)
type A struct
X string
Y int
type B struct
A
Y string
func main()
data := []byte(`"X": "me", "Y": "hi"`)
b := &B
json.Unmarshal(data, b)
fmt.Println(b)
fmt.Println(b.A)
b = &B
data = []byte(`"X": "me", "Y": 123`)
json.Unmarshal(data, b)
fmt.Println(b)
fmt.Println(b.A)
哪些输出:
&me 0 hi
me 0
&me 0
me 0
有没有办法将字段 Y 多态地解组为 int 或字符串?或者甚至因为 B.Y 已定义而完全解组为 A.Y?
我知道有些人可能会建议使用 json.Unmarshall(data, &b.A)
之类的东西来解组,但我不知道我是否可以将它融入我当前的设计中。
【问题讨论】:
也许可以帮助***.com/questions/32428797/… 【参考方案1】:Go 唯一的多态性是接口。嵌入不提供多态性。
如果您尝试在无法假设其中一个字段将是什么类型的情况下解组 JSON,则可以使用类型为 interface
的字段以及类型断言、fmt.Sprint
或反射。你应该使用哪个取决于特定的用例——一旦你得到了价值,你将如何处理它?在某些时候,您必须关心它是 int
还是 string
,这将决定您如何处理该值。
【讨论】:
【参考方案2】:正如 Adrian 所指出的,Go 不支持通过结构嵌入实现多态性。 interface
是保存任何类型的 golang 变量的唯一方法。但是,在您的情况下,您可以实现自定义 Unmarshaler
以使用 json.Number
或 interface
将 JSON 流解码为结构。下面是使用json.Number
的实现。对于更通用的interface
版本,您可以按照 Adrian 的建议实现它。
func (b *B) UnmarshalJSON(js []byte) error
//First: decode stream to anonymous struct
v := struct
X string
Y json.Number
err := json.Unmarshal(js, &v)
if err != nil
return err
//Depends on the v.Y value, choose the holder variable
//If it's convertible to number, assign to A.Y
//otherwise, assign it to b.Y
b.X = v.X
if fv, err := v.Y.Float64(); err == nil
b.A.Y = int(fv)
else
b.Y = v.Y.String()
return nil
工作示例可以在 The Go Playground 中找到。
【讨论】:
正如所写,else 永远不会被执行。调用 err := json.Unmarshal(js, &v) 后的返回 err 导致当数据内容不是数字(例如,“hi”)时不会发生 if/else。有了它,else (b.Y = v.Y.String()) 永远不会发生。此外,不会发生 b.X 的分配。在操场示例中,因此输出中缺少“我”。尽管如此,这个例子还是很有帮助的,所以感谢@putu。以上是关于嵌入式结构的多态 JSON 解组的主要内容,如果未能解决你的问题,请参考以下文章