英文:
How to Unmarshal stream of different types
问题
我有一串不同但已知类型的对象流,我正在努力弄清楚如何将JSON编码的流解组为Go结构体。
这是一个示例切片,仅用于说明目的:
[
{
"uid": "xyz1",
"type": "person",
"name": "John",
"surname": "King"
},
{
"uid": "xyz2",
"type": "thing",
"car": "benz",
"shoes": "nike"
},
{
"uid": "xyz3",
"type": "person",
"name": "Mary",
"surname": "Queen"
}
]
如您所见,有一个type
字段,用于通知接收方对象的类型。
数据在流中映射到以下Go类型,它们“共享”UID
和Type
字段:
type Person struct {
UID string
Type string
Name string
Surname string
}
type Thing struct {
UID string
Type string
Car string
Shoes string
}
我在这里找到了一个类似的问题链接,尽管没有答案,但与我需要处理的情况有些不同。与其保证有一个transaction
键空间,我无法保证负载除了type
和uid
字段之外的样子。
除了深入使用reflect
包之外,是否有其他方法可以实现这一点呢?
英文:
I have a stream of objects of different but known, types and I'm struggling to figure out how to unmarshal the JSON encoded stream into Go structs.
Here is a sample slice for illustration purpose
[
{
"uid": "xyz1",
"type": "person",
"name": "John",
"surname": "King"
},
{
"uid": "xyz2",
"type": "thing",
"car": "benz",
"shoes": "nike"
},
{
"uid": "xyz3",
"type": "person",
"name": "Mary",
"surname": "Queen"
}
]
As you can see there is a type
field that informs the receiver about what is the type of the object.
Data maps into the following Go types in the stream which "share" UID
and Type
fields:
type Person struct {
UID string
Type string
Name string
Surname string
}
type Thing struct {
UID string
Type string
Car string
Shoes string
}
I found a similar question here, though unanswered, it's a bit different from what I need to deal with. Instead of being guaranteed a transaction
keyspace as I've no guarantee what the payload should look like besides the type
and uid
fields.
Is there some way to this other than drowning deeply in reflect
package?
答案1
得分: 1
将其翻译为中文如下:
解析为一个 原始消息 的切片:
var elems []json.RawMessage
err := json.Unmarshal(data, &elems)
if err != nil {
log.Fatal(err)
}
对于切片中的每个元素,先解析一次以找到类型,然后再解析一次以得到具体类型:
for _, elem := range elems {
// 提取类型字段
var t struct {
Type string
}
err := json.Unmarshal(elem, &t)
if err != nil {
log.Fatal(err)
}
// 根据类型字段的值解码为具体类型
switch t.Type {
case "person":
var p Person
err := json.Unmarshal(elem, &p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", p)
case "thing":
var t Thing
err := json.Unmarshal(elem, &t)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", t)
default:
fmt.Printf("未知类型 %s\n", t.Type)
}
}
在 Go playground 上运行代码:点击这里。
英文:
Unmarshal to a slice of raw messages:
var elems []json.RawMessage
err := json.Unmarshal(data, &elems)
if err != nil {
log.Fatal(err)
}
For each element in the slice, unmarshal once to find the type and a second time to the specific type:
for _, elem := range elems {
// Pick out the type field.
var t struct {
Type string
}
err := json.Unmarshal(elem, &t)
if err != nil {
log.Fatal(err)
}
// Decode to specific type based on value of the type field.
switch t.Type {
case "person":
var p Person
err := json.Unmarshal(elem, &p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", p)
case "thing":
var t Thing
err := json.Unmarshal(elem, &t)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", t)
default:
fmt.Printf("unknown type %s\n", t.Type)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论