Proto3:Enumerations - 枚举

When you're defining a message type, you might want one of its fields to only have one of a pre-defined list of values. For example, let's say you want to add a corpus field for each SearchRequest, where the corpus can be UNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS or VIDEO. You can do this very simply by adding an enum to your message definition with a constant for each possible value.
当定义一个message类型时,你可能想其中一个字段的值是你预先定义好的值列表中的一个。举个例子,比如说你想给每个SearchRequest添加一个语料库字段,其值可以是UNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS 或 VIDEO. 你可以通过给你的message定义中添加一个枚举,为每一个可能值设定一个常量来很容易的实现这一点。

In the following example we've added an enum called Corpus with all the possible values, and a field of type Corpus:
接下来的例子我们添加了一个名为Corpus且包含了所有可能值的枚举,和一个类型为Corpus类型的字段:

enum Corpus {
  CORPUS_UNSPECIFIED = 0;
  CORPUS_UNIVERSAL = 1;
  CORPUS_WEB = 2;
  CORPUS_IMAGES = 3;
  CORPUS_LOCAL = 4;
  CORPUS_NEWS = 5;
  CORPUS_PRODUCTS = 6;
  CORPUS_VIDEO = 7;
}
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  Corpus corpus = 4;
}

As you can see, the Corpus enum's first constant maps to zero: every enum definition must contain a constant that maps to zero as its first element. This is because:
正如你所看到的,Corpus枚举的首个常量值为0:每一个枚举定义都必须包含一个值为0的常量作为首元素。这是因为:

  • There must be a zero value, so that we can use 0 as a numeric default value.
    必须有一个零值,这样我们才能使用0作为数字默认值
  • The zero value needs to be the first element, for compatibility with the proto2 semantics where the first enum value is always the default.
    零值需要是首元素,为了兼容proto2默认值总是首元素的语法。

You can define aliases by assigning the same value to different enum constants. To do this you need to set the allow_alias option to true, otherwise the protocol compiler will generate an error message when aliases are found. Though all alias values are valid during deserialization, the first value is always used when serializing.
你可以通过给不同枚举常量指定相同值来定义别名。要做到这一点你需要将allow_alias选项设置为true,否则编译器在发现有别名时会产生一条错误信息。虽然在反序列时所有的别名值都可用,但在序列化时总是使用第一个值。

enum EnumAllowingAlias {
  option allow_alias = true;
  EAA_UNSPECIFIED = 0;
  EAA_STARTED = 1;
  EAA_RUNNING = 1;
  EAA_FINISHED = 2;
}
enum EnumNotAllowingAlias {
  ENAA_UNSPECIFIED = 0;
  ENAA_STARTED = 1;
  // ENAA_RUNNING = 1;  // Uncommenting this line will cause a compile error inside Google and a warning message outside.
  ENAA_FINISHED = 2;
}

Enumerator constants must be in the range of a 32-bit integer. Since enum values use varint encoding on the wire, negative values are inefficient and thus not recommended. You can define enums within a message definition, as in the above example, or outside – these enums can be reused in any message definition in your .proto file. You can also use an enum type declared in one message as the type of a field in a different message, using the syntax _MessageType_._EnumType_.
枚举器常量必须是在32位整型范围内。因为enum值在线路中采用的是varint编码,负数是无效的也是不推荐的。你可以像上边例子一样在message定义中添加枚举类型,或者外部 - .proto文件中的任何message都可以重用这些枚举。你也可以通过_MessageType_._EnumType_语法,在message中使用在其他message类型中定义的枚举类型。

When you run the protocol buffer compiler on a .proto that uses an enum, the generated code will have a corresponding enum for Java, Kotlin, or C++, or a special EnumDescriptor class for Python that's used to create a set of symbolic constants with integer values in the runtime-generated class.
当你运行protocol buffer 编译器来编译包含了一个枚举类型的.proto文件时,生成代码也会为Java, Kotlin, 或 C++提供一个对应的enum类型,或者为Pythone提供一个特殊的EnumDescriptor类,用来在运行时产生的类中生成一系列拥有整型值的符号化常量。

Caution: the generated code may be subject to language-specific limitations on the number of enumerators (low thousands for one language). Please review the limitations for the languages you plan to use.
注意:生成的代码可能收到特定语言的枚举数值(一种语言小于几千的数值)限制。请检查你计划使用语言的限制。

During deserialization, unrecognized enum values will be preserved in the message, though how this is represented when the message is deserialized is language-dependent. In languages that support open enum types with values outside the range of specified symbols, such as C++ and Go, the unknown enum value is simply stored as its underlying integer representation. In languages with closed enum types such as Java, a case in the enum is used to represent an unrecognized value, and the underlying integer can be accessed with special accessors. In either case, if the message is serialized the unrecognized value will still be serialized with the message.
反序列化过程中,未被识别的枚举值将被保留在message中,如何保留这取决于所选语言。在支持开方枚举类型的语言,其值超出指定符号的范围,像C++和Go,未知枚举值将会以基础整型形式简单存储。在带有封闭枚举类型的语言(如Java)中,枚举中的大小用于表示未识别的值,并且可以使用特殊的访问器访问底层整数。无论发生哪种情况,如果messge被序列化,未被识别的值仍将和message一起被序列化。

For more information about how to work with message enums in your applications, see the generated code guide for your chosen language.
有关如何在应用程序中使用message 枚举的更多信息,参阅所选语言的[代码生成指南]

Reserved Values - 保留值

If you update an enum type by entirely removing an enum entry, or commenting it out, future users can reuse the numeric value when making their own updates to the type. This can cause severe issues if they later load old versions of the same .proto, including data corruption, privacy bugs, and so on. One way to make sure this doesn't happen is to specify that the numeric values (and/or names, which can also cause issues for JSON serialization) of your deleted entries are reserved. The protocol buffer compiler will complain if any future users try to use these identifiers. You can specify that your reserved numeric value range goes up to the maximum possible value using the max keyword.
如果你通过整个移除枚举入口的方式更新枚举,或者将其注释掉,后来者在更新该类型时就可以重用我们的数据值。如果他们之后加载相同.proto文件的旧版本,会导致很严重的问题,包括数据腐蚀、隐私问题等。一种解决方案是将你要删除的数值(和、或名称,JSON序列化是同样会出现问题)指定为reversed。后来者如果使用这些已被保留的标识符时protocol buffer编译器会发出警告。你可以通过使用max关键字来指定你保留数值范围是到最大值。

enum Foo {
  reserved 2, 15, 9 to 11, 40 to max;
  reserved "FOO", "BAR";
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容