如何从 interface{} 转换为 struct 实例

我正在研究 Go 模块实现以抽象与其他对等方的通信。该模块背后的想法是通过 MQ 以标准消息格式发送/接收消息,其中几乎可以携带任何类型的“实体”。但是我发现解决 Go 中的类型转换非常困难。


这是我正在尝试做的一个片段(https://play.golang.org/p/Orb1vNdulY1)。


type Message struct {

    Code   string

    Entity interface{}

}


type Cartoon struct {

    Name string

    Show string

}


func main() {

    cartoon := Cartoon{Name: "Doug Funnie", Show: "Doug"}

    msg := Message{Code: "12345", Entity: cartoon}


    payload, err := json.Marshal(msg)

    fmt.Println("JSON Sent:", string(payload))


    // Here json message gets sent to a MQ broker


    // Here json message gets read by a consumer


    var message Message

    err = json.Unmarshal(payload, &message)

    fmt.Println("Message Received:", message)


    var cart Cartoon

    cart = message.Entity.(Cartoon)

    fmt.Println("Cartoon Received:", cart)

}

在这一行,我收到以下错误:


cart = message.Entity.(Cartoon)

恐慌:界面转换:界面{}是地图[字符串]界面{},而不是main.Cartoon


问题是,因为它旨在成为“通用”实体类型的模块,所以在将消息传递给消费者应用程序之前,我不知道实体类型(结构)。


所以我需要一种方法将结构的实例传递给应用程序,甚至允许消费者应用程序转换为它期望接收的类型(结构)。


即使有一种更简单优雅的方式来做我想做的事,即使我必须更改我的 Message 结构,我也可以考虑解决方案。


我想出解决这个问题的唯一方法是将Message.Entity转换为包含原始 json 内容的字符串字段,然后消费者应用程序将其解组为所需的类型。不是那么优雅。


原始字符串/json 解决方案(https://play.golang.org/p/c9bgAbI7SZh)。


有什么想法吗?


PIPIONE
浏览 276回答 3
3回答

繁星淼淼

看起来我可以用一个名为 mapstructure 的库来解决这个问题。var cart Cartoonmapstructure.Decode(message.Entity, &cart)fmt.Println("cartoon:", cart)我在这里做了一个成功的测试:https: //play.golang.org/p/J9V-SFz1pJE

慕桂英4014372

问题询问如何将一个转换interface{}为 Go 类型。OPs 应用程序中更高级别的目标是将 JSON 消息的变体部分转换为 Go 类型。这里回答了更高层次的问题。如果在解组 JSON 时类型已知,则将 Entity 字段设置为指向适当类型值的指针:var cart Cartoonmessage := &Message{Entity: &cart}err := json.Unmarshal(payload, message)在操场上运行它。如果在解码消息的不变部分之后才知道类型,则使用json.RawMessage捕获实体 JSON。一旦知道类型,就解码该 JSON。var entity json.RawMessagemessage := &Message{Entity: &entity}err := json.Unmarshal(payload, &message)// ... determine target entity type using messagevar cart Cartoonerr = json.Unmarshal(entity, &cart)在操场上跑另一种选择是创建类型注册表:var messageTypes = map[string]reflect.Type{    "cartoon": reflect.TypeOf(&Cartoon{}).Elem(),}并从注册表中解码为一种类型:var entity json.RawMessagemessage := &Message{Entity: &entity}err = json.Unmarshal(payload, message)if err != nil {    // handle error}message.Entity = nilif t := messageTypes[message.Type]; t != nil {    v := reflect.New(t).Interface()    err := json.Unmarshal(entity, v)    if err != nil {        // handle error    }    message.Entity = v}

30秒到达战场

有一个解决方案(它不是那么优雅!),如果你保持结构不变。tmp, ok := message.Entity.(map[string]interface{})if ok {    cart.Name = tmp["Name"].(string) // inside bracket depends to the json    cart.Show = tmp["Show"].(string)}https://play.golang.org/p/T9i7pYlk96h你也可以使用反射。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go