当前位置: 首页 > 面试题库 >

基于类型密钥解组动态JSON

江凯风
2023-03-14
问题内容

我在寻找一种不涉及引入一个额外的“通用”字段的溶液等ValueData等这将是该变种领域的占位符。

我有一个JSON规范,它描述了几个大型结构,这些结构主要包含简单的值,但偶尔也有一个结构本身的值,其动态类型取决于某个字段的值。

例如,这两个JSON文档都应解组到相同的Go结构:

{ 
  "some_data": "foo",
  "dynamic_field": { "type": "A", "name": "Johnny" },
  "other_data": "bar"
}

{
  "some_data": "foo",
  "dynamic_field": { "type": "B", "address": "Somewhere" },
  "other_data": "bar"
}

JSON结构已设置,我无法更改。

Go结构必须如下所示:

type BigStruct struct {
  SomeData     string    `json:"some_data"`
  DynamicField Something `json:"dynamic_field"`
  OtherData    string    `json:"other_data"`
}

问题是如何实际执行操作以及该Something类型应为哪种类型。

我首先使其成为一个接口:

type Something interface {
  GetType() string
}

并具有以下几种结构和功能

type BaseDynamicType struct {
  Type string `json:"type"`
}

type DynamicTypeA struct {
  BaseDynamicType
  Name string `json:"name"`
}

type DynamicTypeB struct {
  BaseDynamicType
  Address string `json:"address"`
}

func (d *BaseDynamicType) GetType() string {
  return d.Type
}

原因是,当我获得的实例时BigStruct,我可以这样做:

switch big.DynamicField.GetType() {
  case "A": // do something with big.DynamicField cast to DynamicTypeA
  case "B": // do something with big.DynamicField cast to DynamicTypeB
}

但是,然后我陷入了困境-
这种安排如何配合UnmarshalJSON?我认为BigStruct应该实施UnmarshalJSON将以某种方式检查的Type字段,dynamic_field然后基于该字段,使DynamicFielda
DynamicTypeADynamicTypeB

但是如何?由于递归可能不起作用的一种方法是:

  • 标记DynamicFieldjson:"-"
  • 实施UnmarshalJSONBigStruct
  • 解组JSON成map[string]interface{}BigStructUnmarshalJSON
  • 检查dynamic_field地图中的值,手动构建DynamicTypeADynamicTypeB
  • 再次将相同数据解组到 BigStruct
  • DynamicField用手动创建的值修正

…但是当我尝试将数据解组到a时将导致在第五步中无限递归,BigStruct后者将调用UnmarshalJSON当前正在执行的相同函数。


问题答案:
type BigStruct struct {
    SomeData     string      `json:"some_data"`
    DynamicField DynamicType `json:"dynamic_field"`
    OtherData    string      `json:"other_data"`
}

type DynamicType struct {
    Value interface{}
}

func (d *DynamicType) UnmarshalJSON(data []byte) error {
    var typ struct {
        Type string `json:"type"`
    }
    if err := json.Unmarshal(data, &typ); err != nil {
        return err
    }
    switch typ.Type {
    case "A":
        d.Value = new(TypeA)
    case "B":
        d.Value = new(TypeB)
    }
    return json.Unmarshal(data, d.Value)

}

type TypeA struct {
    Name string `json:"name"`
}

type TypeB struct {
    Address string `json:"address"`
}

https://play.golang.com/p/oKMKQTdzp7s

如果您不想或不能更改DynamicField的类型,则可以将UnmarshalJSON方法放在BigStruct上,并声明一个临时类型以避免递归。

func (b *BigStruct) UnmarshalJSON(data []byte) error {
    var typ struct {
        DF struct {
            Type string `json:"type"`
        } `json:"dynamic_field"`
    }
    if err := json.Unmarshal(data, &typ); err != nil {
        return err
    }

    switch typ.DF.Type {
    case "A":
        b.DynamicField = new(DynamicTypeA)
    case "B":
        b.DynamicField = new(DynamicTypeB)
    }

    type tmp BigStruct // avoids infinite recursion
    return json.Unmarshal(data, (*tmp)(b))
}

https://play.golang.com/p/at5Okp3VU2u



 类似资料:
  • 这是我的密码 抱歉,如果我的代码一团糟。

  • 我试着写一个小函数,它接受两个列表,并根据另一个列表的元素对一个进行排序。所以类似于: 将产生一个排序列表。 然而,可能是一个不同的列表,比如整数、浮点数或其他列表。理想情况下,我希望我的程序能够获取我抛出的任何列表,根据

  • 我有一个应用程序,需要在配置文件中存储一些秘密密码,如数据库和ftp密码/详细信息。我环顾四周,发现了许多使用AES的加密/解密解决方案,但我似乎不知道如何在不改变密钥的情况下使其工作。这意味着我可以加密和解密(使用相同的秘密密钥),但在重启等过程中保持持久性。我似乎无法让秘密钥匙保持不变。下面的示例显示了我的工作方法: 到目前为止还不错。然而,如果我运行它一次,我可能会得到'2Vhht/L80U

  • 本文向大家介绍基于私钥加密公钥解密的RSA算法C#实现方法,包括了基于私钥加密公钥解密的RSA算法C#实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了基于私钥加密公钥解密的RSA算法C#实现方法,是一种应用十分广泛的算法。分享给大家供大家参考之用。具体方法如下: 一、概述 RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。 RSA是被研究得最广泛的公钥算法,从提出

  • 我在我的项目中使用React钩子,需要尝试解决如何在状态值发生变化时动态地将类添加到

  • 我有一个如下所示的数组(这是一个$data变量的打印) 我想做的是在数组中循环,将具有相同prod_键的项目组合成一个项目,并更新总数、数量和重量,这样上面的示例应该如下所示: