【问题标题】:Cast interface{} to struct将 interface{} 转换为结构
【发布时间】:2021-08-06 15:36:31
【问题描述】:

我在一个模块中有以下结构:

type Event struct {
    Name    string      `json:"name"`
    Version string      `json:"version"`
    Payload interface{} `json:"payload"`
}

目标是,我可以接受任意结构为Payload,并使用json.Marshal 和一些消息服务将Event 类型的最终结构作为json 序列化字符串发送。

但是,当我在另一个项目中尝试 json.Unmarshal 时,我无法访问 Event.Payload 内部的字段,因为 Go 显然不知道它的最终类型。

我尝试使用这样的东西:

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

// ...

event := &events.Event{}
event.Payload = &EventPayload{}

if err := json.Unmarshal(msg.Data, event); err != nil {
    return err
}

event.Payload.Name  // Won't work: "type interface{} has no field or method Status"

但是,Go 仍然认为 event.Payloadinterface{}

在这种情况下,我如何告诉 Go 正确的结构类型?

【问题讨论】:

  • Event.Payload 中的值对于 JSON 对象将是 map[string]interface{} 类型,对于 JSON 数组将是 []interface{}。您不能将其强制转换或类型断言为任何其他类型。您只能从 interface{} 值中键入断言 struct 如果它确实包含该类型的值。类型断言不会转换值,也不会神奇地创建新值。
  • Unmarshal 不会创建基于 JSON 的类型。它解组为你给它的类型。您是否希望在接收端解组任何有效负载?为什么不将Unmarshal 直接输入正确的类型?
  • @super 不是说我必须复制Event-struct 的原始代码,只是为Payload-field 使用不同的类型?我的目标是使Event 尽可能通用并重用我之前编写的代码。
  • 作为一般评论:我不认为这个问题那么糟糕!很抱歉,如果这个问题表明我对 Go 缺乏了解。
  • @TimHilt 在Marshal 方面,它可以保持通用,但如果您希望将 json 转换为正确的类型,则需要将这部分代码拆分并使用不同的结构每种Payload,是的。

标签: go struct interface casting type-conversion


【解决方案1】:

您可以完全按照您的描述进行操作,您只需要使用类型断言来获取底层类型即可。 json.Unmarshal,提供了一个预先填充了具体类型的 interface{} 字段,使用该具体类型。

event := &Event{}
event.Payload = &EventPayload{}
msg := []byte(`{"Name": "foo", "Version": "1", "Payload": {"Name": "bar"}}`)

if err := json.Unmarshal(msg, event); err != nil {
    panic(err)
}

pl := event.Payload.(*EventPayload)
fmt.Println(pl.Name)

工作示例(稍作修改以在操场上运行):https://play.golang.org/p/IDXLKeMGw8_1

【讨论】:

  • 哦,所以我只是错过了最后的类型断言!这对我来说很有趣,也很重要。非常感谢。我可以确认,它适用于我的应用程序。 :)
  • 只是出于兴趣;为什么我在这个特定问题上得到如此多的反对票?我不认为,这是一个糟糕的一开始,现在,我知道我是如此接近,我对反对票的理解更少。这可能是不好的做法还是对 Go 的错误使用?
【解决方案2】:

在这种情况下,我如何告诉 Go 正确的结构类型?

你不能。这不是 encoding/json.Unmarshal 的工作方式。您要么必须解组为正确的类型或其他内容,要么使用 json.Raw 消息并进行第二次解组或诸如此类,但您接近它的方式根本行不通。

【讨论】:

    猜你喜欢
    • 2018-12-25
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-10
    • 2015-01-14
    • 2015-01-17
    • 1970-01-01
    相关资源
    最近更新 更多