Protobuf3 枚举
定义消息类型时,您可能希望它的一个字段有一个预定义的值列表。例如,假设您希望为每个SearchRequest添加一个corpus字段,其中语料库可以是UNIVERSAL、WEB、IMAGES、LOCAL、NEWS、PRODUCTS 或VIDEO。您可以非常简单地通过在消息定义中添加枚举来实现这一点,每个可能的值都是一个常量。
在下面的例子中,我们添加了一个名为Corpus 的枚举和一个类型为Corpus的字段:
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4; }
正如你所看到的,Corpus枚举的第一个常量映射到0,每个枚举定义必须包含一个映射到零的常量作为第一个元素。这是因为:
必须有零值,这样我们就可以使用0作为数值默认值。
零值必须为第一个元素,以便与proto 2语义兼容,其中第一个枚举值总是默认的。
可以通过为不同的枚举常量分配相同的值来定义别名。为此,您需要将allow_alias选项设置为true,否则协议编译器会在找到别名时生成错误消息。
enum EnumAllowingAlias { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; } enum EnumNotAllowingAlias { UNKNOWN = 0; STARTED = 1; // RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside. }
枚举数常量必须在32位整数的范围内。由于enum值在传输中使用不同的编码,负值效率低下,因此不推荐使用。您可以在消息定义中定义枚举,如上例所示,也可以在消息定义之外定义枚举——这些枚举可以在 .proto文件中的消息定义中重用。您也可以使用语法MessageType.EnumType,将一条消息中声明的枚举类型用作另一条消息中字段的类型
当你在.proto文件上使用枚举运行协议缓冲区编译器时,生成的代码将具有Java或c++的相应枚举,Python使用一个EnumDescriptor类,用于在运行时生成的类中创建一组具有整数值的符号常量。
在反序列化期间,无法识别的枚举值将保留在消息中,尽管反序列化消息时如何表示这些值取决于编程语言。在支持数值超出指定符号范围的开放式枚举类型的语言中,例如c++和Go,未知的枚举值简单地存储为其底层整数表示。在具有封闭枚举类型的语言(如Java)中,在枚举中无法识别的值可以用特殊的访问器访问。在任一种情况下,如果消息被序列化,则无法识别的值仍将与消息一起序列化。
有关如何在应用程序中使用消息枚举的详细信息,请参阅为您选择的语言生成的代码指南。
保留值
如果通过完全删除枚举条目或注释来更新枚举类型,将来的用户可以在对该类型进行自己的更新时重用数值。如果他们以后加载旧版本的相同 .proto内容,这可能会导致严重的问题。包括数据损坏、隐私漏洞等。确保不会发生这种情况的一种方法是指定保留已删除条目的数值(and/or名称,这也会导致JSON序列化问题)。如果将来有任何用户试图使用这些标识符,协议缓冲区编译器会报错。您可以使用max关键字指定保留的数值范围达到可能的最大值。
enum Foo { reserved 2, 15, 9 to 11, 40 to max; reserved "FOO", "BAR"; }
请注意,不能在同一保留语句中混合字段名和数值。