[英]Golang elegantly JSON decode different structures
我有一個共享字段的不同結構,我需要在Go中將JSON文件解碼為其相應的結構。
例:
type Dog struct {
AnimalType string //will always be "dog"
BarkLoudnessLevel int
}
type Cat struct {
AnimalType string //will always be "cat"
SleepsAtNight bool
}
如果我將其中一種結構作為JSON字符串接收,將其解析為適當結構的最優雅方法是什么?
因此,有兩種方法可以執行此操作,但最簡單的方法可能是對有效負載進行兩次反序列化,並根據有效負載中的“ AnimalType”屬性創建條件分支。 這是一個使用中間反序列化模型的簡單示例:
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有效負載。 因此,例如,如果您正在使用如下所示的有效負載:
{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}}
然后,您可以使用json.RawMessage
類的json.RawMessage
來部分解析結構,然后根據需要有條件地解析其余部分(而不是將所有內容解析兩次),這也會導致更好地分離結構屬性。 這是您將如何做的一個例子:
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")
}
}
並在這里采取行動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.