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
相关产品推荐
相关产品推荐

