最近做一个需求,各种业务消息都会往我的消息队列中写各种类型的数据,服务端需要接受各种不同的参数然后转换为本地数据结构,Go语言不确定上游传过来的数值是什么类型,然后又下面四种解决方案。
1. 类型断言和类型切换
func (MissionEventHandler) Handle(ctx context.Context, message *kafka.Message) error {
var raw map[string]interface{}
err := json.Unmarshal(message.Value, &raw)
if err != nil {
// Handle error
return err
}
switch raw["event"] {
case mission.MISSION_EVENT_PAY_SUCCESS:
uid, ok1 := raw["uid"].(string)
time, ok2 := raw["time"].(string)
num, ok3 := raw["num"].(float64) // JSON numbers are float64 by default
if !ok1 || !ok2 || !ok3 {
// Handle type assertion error
return errors.New("type assertion failed")
}
// Handle the event
// ...
// Add cases for other event types
default:
// Handle unknown event
}
return nil
}
2. 结构体组合
type Event struct {
Event string `json:"event"`
}
type PaySuccessEvent struct {
Event
UID string `json:"uid"`
Time string `json:"time"`
Num int `json:"num"`
}
// ... Define other specific event structs
func (MissionEventHandler) Handle(ctx context.Context, message *kafka.Message) error {
var baseEvent Event
err := json.Unmarshal(message.Value, &baseEvent)
if err != nil {
// Handle error
return err
}
switch baseEvent.Event {
case mission.MISSION_EVENT_PAY_SUCCESS:
var paySuccessEvent PaySuccessEvent
err := json.Unmarshal(message.Value, &paySuccessEvent)
if err != nil {
// Handle error
return err
}
// Handle the event
// ...
// Add cases for other event types
default:
// Handle unknown event
}
return nil
}
3. 使用 json.RawMessage
type GenericEvent struct {
Event string `json:"event"`
Data json.RawMessage `json:"data"`
}
func (MissionEventHandler) Handle(ctx context.Context, message *kafka.Message) error {
var genericEvent GenericEvent
err := json.Unmarshal(message.Value, &genericEvent)
if err != nil {
// Handle error
return err
}
switch genericEvent.Event {
case mission.MISSION_EVENT_PAY_SUCCESS:
var paySuccessEvent PaySuccessEvent
err := json.Unmarshal(genericEvent.Data, &paySuccessEvent)
if err != nil {
// Handle error
return err
}
// Handle the event
// ...
// Add cases for other event types
default:
// Handle unknown event
}
return nil
}
4. 使用 map[string]interface{}
和反射
import (
"reflect"
"encoding/json"
)
func (MissionEventHandler) Handle(ctx context.Context, message *kafka.Message) error {
var raw map[string]interface{}
err := json.Unmarshal(message.Value, &raw)
if err != nil {
// Handle error
return err
}
switch raw["event"] {
case mission.MISSION_EVENT_PAY_SUCCESS:
paySuccessEvent := reflect.New(reflect.TypeOf(PaySuccessEvent{})).Interface()
err := mapstructure.Decode(raw, &paySuccessEvent)
if err != nil {
// Handle error
return err
}
// Handle the event
// ...
// Add cases for other event types
default:
// Handle unknown event
}
return nil
}
在第四种方法中,使用了mapstructure
库,可以将通用的map值解码到相应的结构体中。