You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中如何让WsPayload的Payload成员支持多struct类型?

解决Go中WsPayload的Payload接受多类型的问题

在Go里没有动态变量,但可以通过interface{}(空接口)或者分阶段JSON解析的方式实现需求,以下是具体方案:

方案一:使用空接口interface{}作为Payload类型

直接把WsPayload的Payload字段类型改为interface{},它可以存储任意类型的数据,配合Etype字段做类型断言即可区分具体结构:

type WsPayload struct {
    Action   string              `json:"action"`
    Message  string              `json:"message"`
    Etype    string              `json:"etype"`
    Payload  interface{}         `json:"payload"`  // 修改为interface{}
    Conn     WebSocketConnection `json:"-"`
}

// 保持Earthquake和EventReport结构体不变
type Earthquake struct {
    Body     string `json:"body"`
    Location string `json:"location"`
    Rate     int    `json:"rate_earthquake"`
    Date     string `json:"lat"`
    Time     string `json:"lng"`
}

type EventReport struct {
    Title string   `json:"title"`
    Body  string   `json:"body"`
    Date  string   `json:"date"`
    Time  string   `json:"time"`
    Type  string   `json:"type"`
    Id    string   `json:"id"`
    Photo []string `json:"photo"`
}

解析流程示例

接收到WebSocket的JSON数据后,先反序列化为WsPayload,再根据Etype断言出具体类型:

// 假设data是接收到的JSON字节数组
var wsPayload WsPayload
if err := json.Unmarshal(data, &wsPayload); err != nil {
    // 处理解析错误
    return
}

// 根据Etype判断Payload类型
switch wsPayload.Etype {
case "Earthquake":
    // 先将interface{}转为map,再反序列化为Earthquake结构体
    payloadMap, ok := wsPayload.Payload.(map[string]interface{})
    if !ok {
        // 类型转换失败处理
        return
    }
    payloadBytes, _ := json.Marshal(payloadMap)
    var earthquake Earthquake
    json.Unmarshal(payloadBytes, &earthquake)
    // 此时earthquake就是解析完成的地震数据
case "Event":
    payloadMap, ok := wsPayload.Payload.(map[string]interface{})
    if !ok {
        return
    }
    payloadBytes, _ := json.Marshal(payloadMap)
    var eventReport EventReport
    json.Unmarshal(payloadBytes, &eventReport)
    // 此时eventReport就是解析完成的事件报告数据
}

方案二:分阶段解析JSON(更高效)

先解析外层结构拿到Etype,再针对性解析完整的Payload,避免类型断言的额外开销:

// 定义仅包含外层字段的结构体
type WsPayloadHeader struct {
    Action  string `json:"action"`
    Message string `json:"message"`
    Etype   string `json:"etype"`
}

// 接收数据后先解析头部
var header WsPayloadHeader
if err := json.Unmarshal(data, &header); err != nil {
    return
}

// 根据Etype解析完整的WsPayload
var fullPayload WsPayload
fullPayload.Action = header.Action
fullPayload.Message = header.Message
fullPayload.Etype = header.Etype

switch header.Etype {
case "Earthquake":
    var temp struct {
        WsPayloadHeader
        Payload Earthquake `json:"payload"`
    }
    json.Unmarshal(data, &temp)
    fullPayload.Payload = temp.Payload
case "Event":
    var temp struct {
        WsPayloadHeader
        Payload EventReport `json:"payload"`
    }
    json.Unmarshal(data, &temp)
    fullPayload.Payload = temp.Payload
}

广播注意事项

当你需要把WsPayload序列化后广播给其他客户端时,Go的json.Marshal会自动处理interface{}中的具体类型,直接序列化即可,无需额外处理。

内容的提问来源于stack exchange,提问作者mana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:58:21