Golang可以在C ++中做类似#define的事情吗?

Golang可以在C ++中做类似#define的事情吗?

问题描述:

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++?

With reflection

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().

With constructor functions

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)