AIP-126
Enumerations 枚举
It is common for a field to only accept or provide a discrete and limited set of values. In these cases, it can be useful to use enumerations (generally abbreviated "enums") in order to clearly communicate what the set of allowed values are.
Guidance
APIs may expose enum objects for sets of values that are expected to change infrequently:
// A representation of a book.
message Book {
// Other fields...
// Possible formats in which the book may be published.
enum Format {
// Default value. This value is unused.
FORMAT_UNSPECIFIED = 0;
// The printed format, in hardback.
HARDBACK = 1;
// The printed format, in paperback.
PAPERBACK = 2;
// An electronic book format.
EBOOK = 3;
// An audio recording.
AUDIOBOOK = 4;
}
// The format of the book.
Format format = 99;
// Other fields...
}
- All enum values must use
UPPER_SNAKE_CASE
. - The first value of the enum should be the name of the enum itself
followed by the suffix
_UNSPECIFIED
.- An exception to this rule is if there is a clearly useful zero value. In
particular, if an enum needs to present an
UNKNOWN
, it is usually clearer and more useful for it to be a zero value rather than having both.
- An exception to this rule is if there is a clearly useful zero value. In
particular, if an enum needs to present an
- The other values should not be prefixed by the name of the enum itself.
This generally requires users to write
MyState.MYSTATE_ACTIVE
in their code, which is unnecessarily verbose.- Note that some languages (including C++) hoist enum values into the parent namespace, which can result in conflicts for enums with the same values in the same proto package. To avoid this, multiple enums in the same proto package must not share any values. To avoid sharing values, APIs may prefix enum values with the name of the enum. In this case, they must do so consistently within the enum.
- Enums which will only be used in a single message should be nested within that message. In this case, the enum should be declared immediately before it is used.
-
Enums should document whether the enum is frozen or they expect to add values in the future.
-
所有枚举值必须使用
UPPER_SNAKE_CASE
。 - 枚举的第一个值应该是枚举本身的名称
后跟后缀“_UNSPECIFIED”。
- 如果有一个明显有用的零值,则是此规则的一个例外。在 特别是,如果一个枚举需要呈现一个“未知”,它通常会更清晰 并且更有用的是它是一个零值而不是两者兼而有之。
- 其他值不应以枚举本身的名称为前缀。
这通常需要用户在他们的
代码,这是不必要的冗长。
- 请注意,某些语言(包括 C++)会将枚举值提升到父级 命名空间,这可能导致具有相同值的枚举发生冲突 相同的原型包。为避免这种情况,同一原型中的多个枚举 包不得共享任何值。为了避免共享价值,API 可以 以枚举名称作为枚举值的前缀。在这种情况下,他们 必须在枚举中始终如一地这样做。
- 仅在单个消息中使用的枚举应该嵌套在 那条消息。在这种情况下,枚举应该立即声明 在使用之前。 枚举应该记录枚举是否被冻结或他们希望添加 未来的值。
When to use enums 何时使用枚举
Enums can be more accessible and readable than strings or booleans in many cases, but they do add overhead when they change. Therefore, enums should receive new values infrequently. While the definition of "infrequently" may change based on individual use cases, a good rule of thumb is no more than once a year. For enums that change frequently, the API should use a string and document the format.
Additionally, enums should not be used when there is a competing, widely-adopted standard representation (such as with language codes or media types).
Note: If an enumerated value needs to be shared across APIs, an enum may be used, but the assignment between enum values and their corresponding integers must match.
在许多情况下,枚举比字符串或布尔值更易于访问和可读 情况,但是当它们改变时确实会增加开销。 因此,枚举应该 很少收到新值。 虽然“不经常”的定义可能 根据个人用例进行更改,一个好的经验法则是不超过一次 一年。 对于频繁更改的枚举,API 应该使用字符串和 记录格式。
此外,枚举不应该在有竞争时使用, 广泛采用的标准表示(例如使用 语言代码 或 [媒体类型][])。
注意: 如果一个枚举值需要在 API 之间共享,一个枚举 可以使用,但枚举值与其对应的赋值 整数必须匹配。
Alternatives 备择方案
For enumerated values where the set of allowed values changes frequently, APIs
should use a string
field instead, and must document the allowed
values. String fields with enumerated values should use kebab-case
for
their values.
For enumerated values where there is a competing, widely-adopted standard representation (generally, but not necessarily, a string), that standard representation should be used. This is true even if only a small subset of values are permitted, because using enums in this situation often leads to frustrating lookup tables when trying to use multiple APIs together.
Boolean fields may be used in situations where it is clear that no further
flexibility will be needed. The default value must be false
.
Note: When using protocol buffers, it is impossible to distinguish between
false
and unset. If this is a requirement, an enum may be a better design
choice (although google.protobuf.BoolValue
is also available).
对于允许值集频繁更改的枚举值,API
应该改用“字符串”字段,并且必须记录允许的
值。 具有枚举值的字符串字段应该使用 kebab-case
他们的值。
对于存在竞争的、被广泛采用的标准的枚举值 表示(通常但不一定是字符串),该标准 应该使用表示。 这是真的,即使只有一小部分 值是允许的,因为在这种情况下使用枚举通常会导致 尝试同时使用多个 API 时令人沮丧的查找表。
布尔字段可以用于明确没有进一步的情况
将需要灵活性。 默认值必须为false
。
注意: 使用协议缓冲区时,无法区分
false
并且未设置。 如果这是一个要求,枚举可能是一个更好的设计
选择(尽管 google.protobuf.BoolValue
也可用)。
Further reading
- For states, a special type of enum, see AIP-216.