有没有一种方法可以提取 protobuf 的 oneof int 值?

huangapple go评论83阅读模式
英文:

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

问题

在Go语言中,有没有办法获取protobuf的oneof case的整数值?

在C#中,我可以通过以下方式轻松查询Oneof case的整数值:

opcode = (int)ChannelMessage.ChannelActionOneofCase.Register; // opcode将等于1

然而,在Golang中,似乎没有任何可以轻松提取整数值的方法。

我知道可以根据类型进行switch判断:

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

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

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

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

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;
        ...
	}
}
    

答案1

得分: 1

你是对的,你可以使用类型开关来实现这个功能:

// 我的示例中使用简单的字符串代替了自定义消息。
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("我不知道类型 %T!\n", v)
}

// 你还可以直接询问你的 oneOf 情况并尝试进行类型转换。
val, ok := example.GetRegister().(int) // GetUnregister 是另一个选项。
if ok {
    // 在这里进行黑魔法操作
}

希望对你有帮助!

英文:

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
}

答案2

得分: 1

这是你要翻译的内容:

这可能不是你真正想要做的事情,但是 google.golang.org/protobuf/reflect/protoreflect 包中确实有必要的函数,如果你需要引用作为你的 oneof 一部分的字段的 字段编号

例如,假设你已经将你的 proto 文件导入为 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)将是一个数值类型(protoreflect.FieldNumber = protowire.Number),其底层类型为 int32,你可以将其转换为其他类型。

英文:

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.

huangapple
  • 本文由 发表于 2021年8月4日 10:47:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/68644797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定