为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中,类型名称处理与编码/json 的等效性是什么?

在 Go 中,类型名称处理与编码/json 的等效性是什么?

Go
GCT1015 2022-10-04 19:58:50
散文中的简短描述我有一个情况,我想将JSON数据解封为一个结构数组(或更多),这些结构都实现了一个公共接口。此外,实现接口的所有 eligble 结构类型都有一个公共字段,我在下面的示例中将其命名。鉴别器¹ 允许双唯一地为每个鉴别器值找到正确的结构类型。FooBarMyInterfaceDiscrimininator问题和错误消息但在解封过程中,代码并不“知道”哪个是正确的“目标”类型。取消封马连接失败。不能将对象解封为 main 类型的 Go 值。我的接口姆威在https://play.golang.org/p/Dw1hSgUezLHpackage mainimport (    "encoding/json"    "fmt")type MyInterface interface {    // some other business logic methods go here!    GetDiscriminator() string // GetDiscriminator returns something like a key that is unique per struct type implementing the interface}type BaseStruct struct {    Discriminator string // will always be "Foo" for all Foos, will always be "Bar" for all Bars}type Foo struct {    BaseStruct    // actual fields of the struct don't matter. it's just important that they're different from Bar    FooField string}func (foo *Foo) GetDiscriminator() string {    return foo.Discriminator}type Bar struct {    BaseStruct    // actual fields of the struct don't matter. it's just important that they're different from Foo    BarField int}func (bar *Bar) GetDiscriminator() string {    return bar.Discriminator}其他语言从 .NET 中已知的类型名称处理在流行的.NET JSON框架牛顿软件中,这可以通过称为“类型名称处理”的东西来解决,或者可以使用自定义Json转换器来解决。该框架将在根级别向序列化/封送处理的 JSON 添加类似魔术键的东西,然后用于确定反序列化/取消封送处理的原始类型。"$type"手术室中的多态性¹ 当具有相同基数的多个类型的实例保存在同一表中时,在 ORM 中的术语“多态性”下也会出现类似的情况。通常引入一个鉴别器列,因此在上面的示例中名称。
查看完整描述

1 回答

?
皈依舞

TA贡献1851条经验 获得超3个赞

您可以实现自定义 json。解咒者。为此,您需要使用命名切片类型,而不是未命名的 .[]MyInterface

在自定义取消封口实现中,您可以将 JSON 数组解封为切片,其中切片的每个元素都是一个 json。表示相应 JSON 对象的原始消息。之后,您可以迭代原始消息切片。在循环中,从每个原始消息中仅取消编组字段,然后使用该字段的值来确定可以将完整原始消息解封到的正确类型,最后取消编组完整消息并将结果添加到接收方。DiscriminatorDiscriminator

type MyInterfaceSlice []MyInterface


func (s *MyInterfaceSlice) UnmarshalJSON(data []byte) error {

    array := []json.RawMessage{}

    if err := json.Unmarshal(data, &array); err != nil {

        return err

    }


    *s = make(MyInterfaceSlice, len(array))

    for i := range array {

        base := BaseStruct{}

        data := []byte(array[i])

        if err := json.Unmarshal(data, &base); err != nil {

            return err

        }


        var elem MyInterface

        switch base.Discriminator {

        case "Foo":

            elem = new(Foo)

        case "Bar":

            elem = new(Bar)

        }

        if elem == nil {

            panic("whoops")

        }


        if err := json.Unmarshal(data, elem); err != nil {

            return err

        }

        (*s)[i] = elem

    }

    return nil

}

https://play.golang.org/p/mXiZrF392aV


查看完整回答
反对 回复 2022-10-04
  • 1 回答
  • 0 关注
  • 93 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信