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

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

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

Go
PIPIONE 2022-06-13 16:25:00
我正在研究 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)。有什么想法吗?
查看完整描述

3 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

看起来我可以用一个名为 mapstructure 的库来解决这个问题。


var cart Cartoon

mapstructure.Decode(message.Entity, &cart)

fmt.Println("cartoon:", cart)

我在这里做了一个成功的测试:https: //play.golang.org/p/J9V-SFz1pJE


查看完整回答
反对 回复 2022-06-13
?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

问题询问如何将一个转换interface{}为 Go 类型。OPs 应用程序中更高级别的目标是将 JSON 消息的变体部分转换为 Go 类型。这里回答了更高层次的问题。


如果在解组 JSON 时类型已知,则将 Entity 字段设置为指向适当类型值的指针:


var cart Cartoon

message := &Message{Entity: &cart}

err := json.Unmarshal(payload, message)

在操场上运行它。


如果在解码消息的不变部分之后才知道类型,则使用json.RawMessage捕获实体 JSON。一旦知道类型,就解码该 JSON。


var entity json.RawMessage

message := &Message{Entity: &entity}

err := json.Unmarshal(payload, &message)


// ... determine target entity type using message


var cart Cartoon

err = json.Unmarshal(entity, &cart)

在操场上跑


另一种选择是创建类型注册表:


var messageTypes = map[string]reflect.Type{

    "cartoon": reflect.TypeOf(&Cartoon{}).Elem(),

}

并从注册表中解码为一种类型:


var entity json.RawMessage

message := &Message{Entity: &entity}

err = json.Unmarshal(payload, message)

if err != nil {

    // handle error

}


message.Entity = nil


if t := messageTypes[message.Type]; t != nil {

    v := reflect.New(t).Interface()

    err := json.Unmarshal(entity, v)

    if err != nil {

        // handle error

    }

    message.Entity = v

}


查看完整回答
反对 回复 2022-06-13
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

有一个解决方案(它不是那么优雅!),如果你保持结构不变。


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


你也可以使用反射。


查看完整回答
反对 回复 2022-06-13
  • 3 回答
  • 0 关注
  • 271 浏览
慕课专栏
更多

添加回答

举报

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