Oneof
如果消息包含多个字段,并且最多只能同时设置一个字段,则可以使用oneof功能强制执行此行为并节省内存。
其中Oneof字段与常见字段类似,只是所有字段共享内存空间,最多只能同时设置一个字段。设置其中一个的任何成员将自动清除所有其他成员。您可以使用特殊case()或WhichOneof()方法检查oneof中设置了哪个值(如果有),具体取决于您选择的语言。
使用oneof关键字来在.proto中定义oneof, 后面跟oneof名字, 在这个例子中是test_oneof:
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
将oneof字段添加到oneof定义. 可以添加任意类型的字段, 但是不能使用map 和 repeated字段。
在生成的代码中, oneof字段和普通字段一样有同样的getter和setter方法. 也会有一个特别的方法用来检查哪个值(如果有)被设置了. 可以在所选语言的oneof API中找到更多信息API 参考。
Oneof 特性
- 设置一个oneof字段会自动清除所有其他oneof成员. 所以如果设置多次oneof字段, 只有最后设置的字段依然有值.
- 如果解析器遇到同一个oneof的多个成员, 只有看到的最后一个成员在被解析的消息中被使用.
- oneof不能是repeated字段。
- Reflection APIs work for oneof fields.
- 如果使用c++, 确认代码不会导致内存奔溃.
- 同样在c++中, 如果通过调用Swap()来交换两个带有oneof的消息, 每个消息将会有另外一个消息的oneof。
向后兼容问题
当添加或者删除oneof字段时要小心. 如果检查oneof的值返回None/NOT_SET, 这意味着这个oneof没有被设置或者它被设置到一个字段, 而这个字段是在不同版本的oneof中. 没有办法区分这个差别, 因此没有办法知道一个未知字段是否是oneof的成员.