I defined 3 Message types using protobuf. (MsgA, MsgB, MsgC)
Message MsgA {
string content;
int64 A;
};
Message MsgB {
string content;
char B;
};
Message MsgC {
string content;
double C;
};
and I defined a MsgType to indicate the message is MsgA/MsgB/MsgC
Message MsgType {
string type; // indicate MsgA/ MsgB/ MsgC
};
Then, I generated some messages and stored in a memory map file in this format:
|MsgType|MsgA/MsgB/MsgC|some end marker|
when I read from the buffer, I want to do something similar to this:
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)
...
}
Here is the question: Since each case is quite similar, I want to do something similar to C++
#define CASE(MsgType)\
case #MsgType:\
msg := createObject<msgType>();\
...
switch type {
CASE(MsgA);
CASE(MsgB);
CASE(MsgC);
}
Actually there are many message types, not just A,B,C. There will be repeating codes in each case section. Is there any method in Go to do the similar thing as C++?
It's not the most popular programming language in the world. There are a relatively smaller number of developers using it and there are some good reasons for that. Go is relatively new and immature. It's a bare-bones language lacking a lot of the syntactical sugar that other languages have.
Golang or Go is syntactically similar to C, but only with garbage collection, structural typing, memory safety, and CSP-style concurrency.
Golang is also a multi-paradigm language and supports functional programming. Overall, in terms of design, Golang is better in the sense it's more user-friendly, but if you're looking for more control then C++ is a better choice.
Go (also called Golang or Go language) is an open source programming language used for general purpose. Go was developed by Google engineers to create dependable and efficient software. Most similarly modeled after C, Go is statically typed and explicit.
You could use a map where you store type descriptors mapped from type name (e.g. MsgType.type
field). The type descriptor may be reflect.Type
.
So you can get the type descriptor with a simple map lookup, and you can use reflect.New()
to get a pointer to a new, zeroed value of this type.
For example:
var registry = map[string]reflect.Type{
"MsgA" : reflect.TypeOf(MsgA{}),
"MsgB" : reflect.TypeOf(MsgB{}),
"MsgC" : reflect.TypeOf(MsgC{}),
}
And the common code when reading a message:
typeToRead := registry[msgType.GetType()]
msg := reflect.New(typeToRead).Interface()
err := prto.Unmarshal(byteArrayforMsg, msg.(proto.Message))
Note: msg
will be of static type interface{}
, and it wraps a pointer to one of your message types, e.g. the type of the concrete value stored it in may be *MsgA
, exactly what you have to pass to proto.Unmarshal()
.
Another way to get a new message value could be to use constructor functions, so no reflection will be needed.
This is how it would look like:
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) },
}
And using it:
creator := registry[msgType.GetType()]
msg := creator()
err := prto.Unmarshal(byteArrayforMsg, msg)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With