英文:
How to unmarshall a json file with nested objects which can be different from eachother in Golang
问题
以下是翻译好的内容:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Occupation string `json:"occupation"`
Social map[string]string `json:"social"`
}
type Social struct {
Facebook string `json:"facebook"`
Twitter string `json:"twitter"`
}
这是正确的反序列化 JSON 的方式吗?由于 Social
结构体需要一个用于 Facebook 和一个用于 Twitter 的不同字符串,所以会失败吗?有没有更好的方法来反序列化这样的 JSON?
英文:
With a json file that looks something like this, where someone can only have one social but it could be different depending on the person, how would I unmarshal this into a struct.
[
{
"name": "Bob",
"age": 14,
"occupation": "Builder",
"social": {
"facebook": "Bob_the_builder"
},
{
"name": "Alice",
"age": 14,
"occupation": "Builder",
"social": {
"twitter": "Alice_the_builder"
}
]
My current struct variables looks like this.
type User struct {
Name String 'json:"name"'
Age int 'json:"age"'
Occupation String 'json:"occupation"'
Social Social 'json:"social"'
}
type Social struct {
Facebook String 'json:"facebook"'
Twitter String 'json:"twitter"'
}
Is this the correct way to unmarshall the json or will it fail as the 'Social' struct wants two different strings one for Facebook and one for Twitter. Is there a better way to unmarshall a json like this?
答案1
得分: 2
你提供的示例应该可以工作,只是会使其中一个字符串为空。
如果你想用两个不同的结构体替换Social
,你可以将Social
定义为一个接口,然后让这两个新的结构体都实现该接口。然后使用json.RawMessage
来延迟对social
中的JSON进行解析。以下是godocs中给出的示例代码:
import (
"encoding/json"
"fmt"
"log"
)
func main() {
type Color struct {
Space string
Point json.RawMessage // 延迟解析,直到我们知道颜色空间
}
type RGB struct {
R uint8
G uint8
B uint8
}
type YCbCr struct {
Y uint8
Cb int8
Cr int8
}
var j = []byte(`[
{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
{"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255}}
]`)
var colors []Color
err := json.Unmarshal(j, &colors)
if err != nil {
log.Fatalln("error:", err)
}
for _, c := range colors {
var dst interface{}
switch c.Space {
case "RGB":
dst = new(RGB)
case "YCbCr":
dst = new(YCbCr)
}
err := json.Unmarshal(c.Point, dst)
if err != nil {
log.Fatalln("error:", err)
}
fmt.Println(c.Space, dst)
}
}
在这个示例中,他们使用一个字符串来指示应该将Point
解析为哪个结构体。在你的情况下,你可能需要先将social
解析为map[string]interface{}
,然后根据字段确定应该使用哪种类型。或者在User
结构体中添加一个socialType
字段。
英文:
The example you provided should work, it will just leave one of your strings empty.
If you want to replace Social
with 2 different structs, you can make Social
an interface which both new structs implement. Then use json.RawMessage
to delay the unmarshalling of the json in social
. This is the example given in the godocs:
import (
"encoding/json"
"fmt"
"log"
)
func main() {
type Color struct {
Space string
Point json.RawMessage // delay parsing until we know the color space
}
type RGB struct {
R uint8
G uint8
B uint8
}
type YCbCr struct {
Y uint8
Cb int8
Cr int8
}
var j = []byte(`[
{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
{"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255}}
]`)
var colors []Color
err := json.Unmarshal(j, &colors)
if err != nil {
log.Fatalln("error:", err)
}
for _, c := range colors {
var dst interface{}
switch c.Space {
case "RGB":
dst = new(RGB)
case "YCbCr":
dst = new(YCbCr)
}
err := json.Unmarshal(c.Point, dst)
if err != nil {
log.Fatalln("error:", err)
}
fmt.Println(c.Space, dst)
}
}
In this example they use a string to indicate as which struct to unmarshall Point
. In your case you may need to first unmarshall social
as map[string]interface{}
and determine which type should be used based on the fields. Or add a socialType
field to the User
struct.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论