json - Golang 优雅地解码不同的 JSON 结构

标签 json parsing go

我有不同的结构共享一个字段,我需要将一个 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/

相关文章:

javascript - 以 JSON 形式返回字典并使用 JS 函数成功访问其内容 - C#

json - 如何使用jq解析一个json对象数组

go - 使用未从包中导出的类型

json - 带有 JSON 层的 PDF 注释器

javascript - 从 Ajax-JSON 中提取元素

php - 在没有类依赖的自定义类/子系统中使用 Laravel 4 模型

android - 在android中解析JSON对象

sql - t-sql 用 csv 字符串查找特定值

windows - 在 Go 中请求 UAC 提升

go - 在DDD(纯净/六角形)架构中处理数据库连接和Env配置