是否需要在protobuf中使用“oneof”?

5

我想制作一个能够包含多种不同事件类型的protobuf Event消息。下面是一个例子:

message Event {
    required int32 event_id = 1;

    oneof EventType {
        FooEvent foo_event = 2;
        BarEvent bar_event = 3;
        BazEvent baz_event = 4;
    }
}

这很正常,但有一件事情让我很困扰,那就是EventType是可选的:我可以只编码一个带有event_id的对象,protobuf不会报错。
>>> e = test_pb2.Event()
>>> e.IsInitialized()
False
>>> e.event_id = 1234
>>> e.IsInitialized()
True

有没有办法要求设置EventType?如果使用Python,是否会有影响?

2个回答

25
根据Protocol Buffers文档,不推荐使用并且在proto3中已删除了required字段规则。

永远需要谨慎地标记字段为必需的。如果您希望在某个时间点停止编写或发送必需字段,则更改该字段为可选字段将有问题;旧的读取器将认为没有这个字段的消息是不完整的,并可能无意中拒绝或丢弃它们。您应该考虑为您的缓冲区编写特定于应用程序的自定义验证程序。Google的一些工程师得出结论,使用必需字段比好处要小;他们更喜欢只使用可选和重复字段。然而,这种观点并不普遍存在。

正如上述文件所说,您应该考虑使用应用程序特定的验证方法,而不是将字段标记为required

没有办法将oneof标记为“required”(即使在proto2中),因为当oneof被引入时,已经广泛接受字段可能永远不应该是“required”,因此设计人员没有费心实现让oneof成为必需的方式。


2
我认为这是一个很好的答案,不应该被投票否决。我添加了一段话将其与“oneof”联系起来,以防这是投票否决的原因。 - Kenton Varda

1

使用options语法,可以指定验证规则并自动生成验证程序的代码。

您可以像这样使用https://github.com/envoyproxy/protoc-gen-validate

import "validate/validate.proto";

message Event {
    required int32 event_id = 1;

    oneof EventType {
        option (validate.required) = true;

        FooEvent foo_event = 2;
        BarEvent bar_event = 3;
        BazEvent baz_event = 4;
    }
}

“您应该考虑编写特定于应用程序的自定义验证例程,而不是使用缓冲区。” 这就是我们正在自动生成此类自定义验证例程的原因。
但是,请等一下,这是否违背了protobuf规范的精神?为什么“必需”的不好,而“验证”则好? 我的答案是,protobuf规范非常关心“代理”,即序列化/反序列化消息的软件,但几乎没有自己的业务逻辑。这样的软件可以简单地省略验证(这是一个选项),但它不能省略“必需”(它必须使消息无法解析)。
对于业务逻辑方面,在我的经验中,所有这些都不是大问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接