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

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)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘