douba3975
2018-07-12 15:02
浏览 301
已采纳

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

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dongmi4927 2018-07-12 15:22
    已采纳

    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)
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题