有没有办法提取 protobuf oneof int 值?

Is there a way to extract a protobuf oneof int value?

TL;DR: 在 Go 中,有没有办法获取 protobuf oneof case 的整数值?

详情:

在 C# 中,我可以使用类似以下内容轻松查询 Oneof 案例的整数值:

opcode = (int)ChannelMessage.ChannelActionOneofCase.Register; // opcode will equal 1

但是在 Golang 中,似乎没有任何东西可以用来轻松提取整数值。

我知道我可以打开类型本身:

switch m.ChannelAction.(type) {
    
    case *proto.ChannelMessage_Register:
    ...

然而,在我的情况下,这将要求我解组每条消息,这对于某些类型来说并不是绝对必要的,因为我每次都需要发送操作码。

如果有帮助,我的 ChannelMessage 类型如下所示:

message ChannelMessage
{
    oneof ChannelAction
    {
        ChannelRegister register = 1;
        ChannelUnregister unregister = 2;
        ...
    }
}
    

你是对的,你可以通过类型切换来做到这一点:

// 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
}

可能 不是您实际想要做的,但是 google.golang.org/protobuf/reflect/protoreflect package does have the necessary functions, if you need to refer to the field numbers 属于您 oneof 的字段的一部分。

例如,假设您已将原型导入为 pb,要按名称获取数字 1(如在您的 C# 示例中),您可以执行以下操作:

desc := (&pb.ChannelMessage{}).ProtoReflect().Descriptor()
opcode := desc.Fields().ByName("register").Number()

(这并非严格特定于 oneof,因为 oneof 字段实际上只是常规消息字段,带有附加约束,只能设置其中一个。)

或者在消息 m 中找出 oneof 字段设置为哪个字段编号而不写出类型开关,假设您知道其中一个肯定已设置,您可以这样做:

ref := m.ProtoReflect()
desc := ref.Descriptor()
num := ref.WhichOneof(desc.Oneofs().ByName("ChannelAction")).Number()

在这两种情况下,结果 (opcodenum) 都将是具有基础类型 int32 的数字类型 (protoreflect.FieldNumber = protowire.Number),您可以将其转换到.