Reputation: 15
TL;DR: In Go, is there any way to get the integer value of a protobuf oneof case?
Detail:
In C# I can easily query the integer value of a Oneof case using something like the following:
opcode = (int)ChannelMessage.ChannelActionOneofCase.Register; // opcode will equal 1
However in Golang, there does not appear to be anything that I can use to easily extract that integer value.
I know that I can switch on the type itself:
switch m.ChannelAction.(type) {
case *proto.ChannelMessage_Register:
...
however in my case this will require me to unmarshal every message, which for certain types isn't strictly necessary since I'm required to send the opcode along every time.
If it's helpful, my ChannelMessage type looks like the following:
message ChannelMessage
{
oneof ChannelAction
{
ChannelRegister register = 1;
ChannelUnregister unregister = 2;
...
}
}
Upvotes: 1
Views: 8258
Reputation: 711
It's probably not what you want to actually do, but the google.golang.org/protobuf/reflect/protoreflect package does have the necessary functions, if you need to refer to the field numbers of the fields that are part of your oneof
.
For example, assuming you've imported your protos as pb
, to get the number 1 by name (as in your C# example) you can do:
desc := (&pb.ChannelMessage{}).ProtoReflect().Descriptor()
opcode := desc.Fields().ByName("register").Number()
(This isn't strictly specific to the oneof
, since oneof
fields are really just regular message fields with an additional constraint that only one of them may be set.)
Or to figure out which field number a oneof
field is set to in message m
without writing out a type switch, assuming you know one of them has definitely been set, you can do:
ref := m.ProtoReflect()
desc := ref.Descriptor()
num := ref.WhichOneof(desc.Oneofs().ByName("ChannelAction")).Number()
In both cases the result (opcode
, num
) will be a numeric type (protoreflect.FieldNumber = protowire.Number) that has an underlying type of int32
you can convert it to.
Upvotes: 2
Reputation: 5405
You are right, you can do that with type switch:
// my example used simple strings instead of custom messages.
example := proto.ChannelMessage{
ChannelAction: &pbExample.ChannelMessage_Register{"foobar"},
}
t := example.GetChannelAction()
switch v := t.(type) {
case *pbExample.ChannelMessage_Register:
fmt.Printf("register\n")
case *pbExample.ChannelMessage_Unregister:
fmt.Printf("unregister\n")
default:
fmt.Printf("I don't know about type %T!\n", v)
}
// what you also can do is to ask directly your oneOf case and try to typecast it.
val, ok := example.GetRegister().(int) // GetUnregister is other option.
if ok {
// black magic happens here
}
Upvotes: 2