我有不同的结构共享一个字段,我需要将一个 JSON 文件解码成它在 Go 中的相应结构。
例子:
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")
}
}
查看实际效果 here .
IMO 解决此问题的更好方法是将有效载荷的“元数据”移动到父结构中,尽管这需要修改预期的 json 有效载荷。因此,例如,如果您使用的有效载荷看起来像:
{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}}
然后您可以使用类似 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")
}
}
并在行动中 here .
关于json - Golang 优雅地解码不同的 JSON 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47911187/