Cub*_*Mew 5 polymorphism macros go protocol-buffers
我使用 protobuf 定义了 3 种消息类型。(MsgA, MsgB, MsgC)
Message MsgA {
string content;
int64 A;
};
Message MsgB {
string content;
char B;
};
Message MsgC {
string content;
double C;
};
Run Code Online (Sandbox Code Playgroud)
我定义了一个 MsgType 来指示消息是 MsgA/MsgB/MsgC
Message MsgType {
string type; // indicate MsgA/ MsgB/ MsgC
};
Run Code Online (Sandbox Code Playgroud)
然后,我生成了一些消息并以这种格式存储在内存映射文件中:
|MsgType|MsgA/MsgB/MsgC|some end marker|
Run Code Online (Sandbox Code Playgroud)
当我从缓冲区读取时,我想做类似的事情:
msgType := &MsgType{}
err := proto.Unmarshal(byteArrayforMsgType, msgType)
...
switch msgType.GetType() {
case "MsgA":
a := &MsgA{}
err := prto.Unmarshal(byteArrayforMsg, a)
...
case "MsgB":
b := &MsgB{}
err := prto.Unmarshal(byteArrayforMsg, b)
...
case "MsgC":
c := &MsgC{}
err := prto.Unmarshal(byteArrayforMsg, c)
...
}
Run Code Online (Sandbox Code Playgroud)
问题来了:既然每个案例都非常相似,我想做一些类似于C++的事情
#define CASE(MsgType)\
case #MsgType:\
msg := createObject<msgType>();\
...
switch type {
CASE(MsgA);
CASE(MsgB);
CASE(MsgC);
}
Run Code Online (Sandbox Code Playgroud)
实际上有很多消息类型,不仅仅是A,B,C。每个案例部分都会有重复的代码。Go 中有什么方法可以做与 C++ 类似的事情吗?
您可以使用映射来存储从类型名称(例如MsgType.type字段)映射的类型描述符。类型描述符可以是reflect.Type。
因此,您可以通过简单的映射查找来获取类型描述符,并且可以使用它reflect.New()来获取指向该类型的新的归零值的指针。
例如:
var registry = map[string]reflect.Type{
"MsgA" : reflect.TypeOf(MsgA{}),
"MsgB" : reflect.TypeOf(MsgB{}),
"MsgC" : reflect.TypeOf(MsgC{}),
}
Run Code Online (Sandbox Code Playgroud)
以及读取消息时的通用代码:
typeToRead := registry[msgType.GetType()]
msg := reflect.New(typeToRead).Interface()
err := prto.Unmarshal(byteArrayforMsg, msg.(proto.Message))
Run Code Online (Sandbox Code Playgroud)
注意:msg将是静态类型interface{},并且它包装了一个指向您的消息类型之一的指针,例如,存储它的具体值的类型可能是*MsgA,正是您必须传递给的proto.Unmarshal()。
获取新消息值的另一种方法是使用构造函数,因此不需要反射。
它看起来是这样的:
var registry = map[string]func() proto.Message{
"MsgA" : func() proto.Message { return new(MsgA) },
"MsgB" : func() proto.Message { return new(MsgB) },
"MsgC" : func() proto.Message { return new(MsgC) },
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
creator := registry[msgType.GetType()]
msg := creator()
err := prto.Unmarshal(byteArrayforMsg, msg)
Run Code Online (Sandbox Code Playgroud)