Proto3:Oneof

If you have a message with many fields and where at most one field will be set at the same time, you can enforce this behavior and save memory by using the oneof feature.
如果你有一个有很多字段的message,而这些字段至少有一个字段需要同时被设置,你可以使用oneof特性来强制执行这种行为,并且可以节省内存。

Oneof fields are like regular fields except all the fields in a oneof share memory, and at most one field can be set at the same time. Setting any member of the oneof automatically clears all the other members. You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.
除了在oneof中的所有字段共享内存并且至多一个字段可以被同时设置值之外,Oneof 字段和常规字段一样。设置任何oneof的成员后都会自动清理其他所有成员。你可以通过特殊case()或WhichOneof()方法检测oneof中哪个值被设置了(如果有的话),取决于你所选择的语言。

Note that if multiple values are set, the last set value as determined by the order in the proto will overwrite all previous ones.
注意如果多个值被设置,最终哪个值被设置是由proto中的顺序决定,并且会覆盖之前的设置。

Using Oneof - 使用Oneof

To define a oneof in your .proto you use the oneof keyword followed by your oneof name, in this case test_oneof:
为了在你的.proto中定义一个oneof,你可以使用oneof关键字再加上你的oneof名称,在test_oneof案例中:

message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

You then add your oneof fields to the oneof definition. You can add fields of any type, except map fields and repeatedfields.
你在oneof定义中添加了你的oneof字段,除了map字段和repeated字段,你可以添加任意类型的字段。

In your generated code, oneof fields have the same getters and setters as regular fields. You also get a special method for checking which value (if any) in the oneof is set. You can find out more about the oneof API for your chosen language in the relevant API reference.
在你生成的代码中,和常规字段一样oneof字段也有getter和setter方法。你也会活得一个特殊方法用于检测oneof中哪个字段被设置了值(如果有的话)。在相关API 参考中你可以查看更多你所选语言的oneof API的信息

Oneof Features - Oneof 特性

  • Setting a oneof field will automatically clear all other members of the oneof. So if you set several oneof fields, only the last field you set will still have a value.
    设置一个oneof字段后会自动清除oneof所有其他成员的值。所以如果你设置了多个oneof字段,仅最后一个字段会有值。
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
// Calling mutable_sub_message() will clear the name field and will set
// sub_message to a new instance of SubMessage with none of its fields set
message.mutable_sub_message();
CHECK(!message.has_name());
  • If the parser encounters multiple members of the same oneof on the wire, only the last member seen is used in the parsed message.
    如果解析器在线路中遇到同一oneof的多个成员,则在message解析中仅使用最后一个看到的成员。

  • A oneof cannot be repeated.
    oneof不可重复。

  • Reflection APIs work for oneof fields.
    Reflection APIs对oneof 字段同样生效。

  • If you set a oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire.
    如果你讲oneof 字段设置为默认值(比如将一个int32类型的oneof字段设置为0),则oneof字段的“case”将会被设置,其值会在线路中被序列化。

  • If you're using C++, make sure your code doesn't cause memory crashes. The following sample code will crash because sub_message was already deleted by calling the set_name() method.
    如果你正在使用C++,保证你的代码不会导致内存崩溃。下面例子中简单代码就会崩溃,因为在set_name()方法调用后sub_message已经被删除。

SampleMessage message;
SubMessage* sub_message = message.mutable_sub_message();
message.set_name("name");      // Will delete sub_message
sub_message->set_...            // Crashes here
  • Again in C++, if you Swap() two messages with oneofs, each message will end up with the other’s oneof case: in the example below, msg1 will have a sub_message and msg2 will have a name.
    同样在C++中,如果你给两个oneof message调用Swap(),每个message会以另一个message的oneof情况结束:在下面的例子中,msg1会拥有一个sub_message而msg2会有一个name。
SampleMessage msg1;
msg1.set_name("name");
SampleMessage msg2;
msg2.mutable_sub_message();
msg1.swap(&msg2);
CHECK(msg1.has_sub_message());
CHECK(msg2.has_name());

Backwards-compatibility issues - 向下兼容问题

Be careful when adding or removing oneof fields. If checking the value of a oneof returns None/NOT_SET, it could mean that the oneof has not been set or it has been set to a field in a different version of the oneof. There is no way to tell the difference, since there's no way to know if an unknown field on the wire is a member of the oneof.
添加或移除oneof 字段时需要当心。如果检测oneof字段值返回None/NOT_SET,这可能意味着oneof字段未被设置或者在一个不同版本中其中有一个字段已经被设置。无法确定不同,因为无法知道线路中的一个未知字段是否是oneof的一个成员。

Tag Reuse Issues - 标签重用问题

Move fields into or out of a oneof: You may lose some of your information (some fields will be cleared) after the message is serialized and parsed. However, you can safely move a single field into a new oneof and may be able to move multiple fields if it is known that only one is ever set.
移入或移出字段到oneof:在messag被序列化或解析后,你可能会丢失你的某些信息(某些字段被清除)。然而,你可以安全地将一个单一字段移动到一个新的oneof中,也许能够移动多个字段如果已知只有一个曾被设置过。

Delete a oneof field and add it back: This may clear your currently set oneof field after the message is serialized and parsed.
Split or merge oneof: This has similar issues to moving regular fields.
删除一个oneof字段然后添加回去:在message被序列化或解析后,这样做可能会清楚掉你当前设置了的oneof 字段。
分开或合并oneof:这和移动常规字段面临同样的问题。

你可能感兴趣的:(Proto3:Oneof)