Golang优雅地用JSON解码不同的结构 [英] Golang elegantly JSON decode different structures
问题描述
我有一个共享字段的不同结构,我需要在Go中将JSON文件解码为其相应的结构.
I have different structures that share a field and I need to decode a JSON file into its corresponding structure in Go.
示例:
type Dog struct {
AnimalType string //will always be "dog"
BarkLoudnessLevel int
}
type Cat struct {
AnimalType string //will always be "cat"
SleepsAtNight bool
}
如果我将其中一种结构作为JSON字符串接收,将其解析为适当结构的最优雅的方法是什么?
If I am receiving one of these structures as a JSON string, what would be the most elegant way of parsing it into its proper structure?
推荐答案
因此,有几种方法可以做到这一点,但最简单的方法可能是对反序列化有效负载两次,并根据其中的"AnimalType"属性创建条件分支.您的有效载荷.这是一个使用中间反序列化模型的简单示例:
So, there are a couple ways of doing this, but the easiest is probably deserializing the payload twice and having conditional branches based off of the "AnimalType" attribute in your payload. Here's a simple example using an intermediate deserialization model:
package main
import (
"fmt"
"encoding/json"
)
type Dog struct {
AnimalType string //will always be "dog"
BarkLoudnessLevel int
}
type Cat struct {
AnimalType string //will always be "cat"
SleepsAtNight bool
}
var (
payloadOne = `{"AnimalType":"dog","BarkLoudnessLevel":1}`
payloadTwo = `{"AnimalType":"cat","SleepsAtNight":false}`
)
func main() {
parseAnimal(payloadOne)
parseAnimal(payloadTwo)
}
func parseAnimal(payload string) {
animal := struct{
AnimalType string
}{}
if err := json.Unmarshal([]byte(payload), &animal); err != nil {
panic(err)
}
switch animal.AnimalType {
case "dog":
dog := Dog{}
if err := json.Unmarshal([]byte(payload), &dog); err != nil {
panic(err)
}
fmt.Printf("Got a dog: %v\n", dog)
case "cat":
cat := Cat{}
if err := json.Unmarshal([]byte(payload), &cat); err != nil {
panic(err)
}
fmt.Printf("Got a cat: %v\n", cat)
default:
fmt.Println("Unknown animal")
}
}
请在此处查看.
IMO解决此问题的更好方法是将有效负载的元数据"移动到父结构中,尽管这需要修改预期的json有效负载.因此,例如,如果您正在使用如下所示的有效负载:
IMO a better way of approaching this is moving the "metadata" for the payload into a parent structure, though this requires modifying the expected json payload. So, for example, if you were working with payloads that looked like:
{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}}
然后,您可以使用诸如json.RawMessage
之类的方法来部分解析结构,然后根据需要有条件地解析其余部分(而不是将所有内容解析两次),这也会导致更好地分离结构属性.这是您如何执行此操作的示例:
Then you could use something like json.RawMessage
to partially parse the structure and then conditionally parse the rest as needed (rather than parsing everything twice)--also results in a nicer separation of structure attributes. Here's an example of how you'd do that:
package main
import (
"encoding/json"
"fmt"
)
type Animal struct {
AnimalType string
Animal json.RawMessage
}
type Dog struct {
BarkLoudnessLevel int
}
type Cat struct {
SleepsAtNight bool
}
var (
payloadOne = `{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}}`
payloadTwo = `{"AnimalType":"cat", "Animal":{"SleepsAtNight": false}}`
)
func main() {
parseAnimal(payloadOne)
parseAnimal(payloadTwo)
}
func parseAnimal(payload string) {
animal := &Animal{}
if err := json.Unmarshal([]byte(payload), &animal); err != nil {
panic(err)
}
switch animal.AnimalType {
case "dog":
dog := Dog{}
if err := json.Unmarshal(animal.Animal, &dog); err != nil {
panic(err)
}
fmt.Printf("Got a dog: %v\n", dog)
case "cat":
cat := Cat{}
if err := json.Unmarshal(animal.Animal, &cat); err != nil {
panic(err)
}
fmt.Printf("Got a cat: %v\n", cat)
default:
fmt.Println("Unknown animal")
}
}
并且在此处.
这篇关于Golang优雅地用JSON解码不同的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!