前言
本教程用于说明 Protocol Buffers 中一些关键字的作用和用法,其他教程参见:
正文
Oneof
当我们的 Message 中包含多个字段但是只允许其中一个字段生效的时候可以使用oneof关键字,这样在编码得到时候会节省一部分内存。
oneof内声明字段和常规声明字段得到方式类似,但是需要注意oneof里面的字段使用的编号适合外部的字段编号同级的,这里需要注意不要让编号冲突。oneof中的多个字段只允许我们生效其中一个,这意味着当我们设置其中一个字段的时候,都会清除掉其他所有的成员。我们可以使用case()或WhichOneof方法去获取被赋值的字段,具体使用哪个方法取决于具体的编程语言。
如何使用
在.proto中定义一个oneof类型,只需要在oneof关键字后边跟上字段名称即可。示例如下:
messageSampleMessage{oneoftest_oneof{stringname=4;SubMessagesub_message=9;}}
我们可以将我们需要的字段都添加到oneof的定义里面,这些字段可以是任意类型,但不能是repeated修饰的字段。
Oneof 的特性
赋值oneof中定义的字段时会自动清除其他所有字段值,所以在我们设置了多个oneof中的字段的时候,仅最后最后设置的那个字段有值。
1 2 3 4 5SampleMessagemessage;message.set_name("name");CHECK(message.has_name());message.mutable_sub_message();// name 字段的值会被清除CHECK(!message.has_name());
oneof中不能使用repeated修饰的字段。
当解析器遇到同一个oneof中的多个成员字段时,只有最后一个字段会被解析。
可以对oneof类型的字段使用反射。
如果将oneof中的字段设置为默认值,该字段在传输过程中会被序列化(非oneof字段的默认值是不会被序列化的)。
在C++ 中需要注意内存越界的问题,下面的代码会产生内存越界,因为在调用set_name()的时候删除了sub_message。