以下是一个示例(另请参阅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)
之类的东西进行解组,但我不知道我是否可以将其纳入我目前的设计中。
答案 0 :(得分:2)
Go的唯一多态是接口。嵌入不提供多态性。
如果您尝试解组JSON,而不能假设其中一个字段类型,则可以使用类型为interface{}
的字段以及类型断言{ {1}},或反思。你应该使用哪种取决于具体的用例 - 一旦你获得了价值,你将用它做什么?在某些时候,您必须关心它是fmt.Sprint
还是int
,这将决定您如何处理该值。
答案 1 :(得分:1)
正如Adrian所指出的,Go不支持通过struct embedding进行多态性。 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中找到工作示例。