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

散文中的简短描述

我有一个情况,我想将JSON数据解封为一个结构数组(或更多),这些结构都实现了一个公共接口。此外,实现接口的所有 eligble 结构类型都有一个公共字段,我在下面的示例中将其命名。鉴别器¹ 允许双唯一地为每个鉴别器值找到正确的结构类型。FooBarMyInterfaceDiscrimininator

问题和错误消息

但在解封过程中,代码并不“知道”哪个是正确的“目标”类型。取消封马连接失败。

不能将对象解封为 main 类型的 Go 值。我的接口

姆威在

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

package main


import (

    "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 中的术语“多态性”下也会出现类似的情况。通常引入一个鉴别器列,因此在上面的示例中名称。


GCT1015
浏览 94回答 1
1回答

皈依舞

您可以实现自定义 json。解咒者。为此,您需要使用命名切片类型,而不是未命名的 .[]MyInterface在自定义取消封口实现中,您可以将 JSON 数组解封为切片,其中切片的每个元素都是一个 json。表示相应 JSON 对象的原始消息。之后,您可以迭代原始消息切片。在循环中,从每个原始消息中仅取消编组字段,然后使用该字段的值来确定可以将完整原始消息解封到的正确类型,最后取消编组完整消息并将结果添加到接收方。DiscriminatorDiscriminatortype MyInterfaceSlice []MyInterfacefunc (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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go