Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can golang do similar thing like #define in C++?

Tags:

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

like image 355
Cubey Mew Avatar asked Jul 12 '18 15:07

Cubey Mew


People also ask

Why is Golang not popular?

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.

Is Golang similar to C?

Golang or Go is syntactically similar to C, but only with garbage collection, structural typing, memory safety, and CSP-style concurrency.

Is C++ better than Go?

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.

Is Go language same as Golang?

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.


1 Answers

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)
like image 57
icza Avatar answered Oct 13 '22 04:10

icza