ProtoBuf的字段编号
消息定义中的每个字段都有一个唯一的编号。这些字段编号用于在消息二进制格式中标识您的字段,一旦您的消息类型被使用,就不应更改(消息类型被使用了,更改字段编码会影响已有数据的编解码)。
1到15范围内的字段编号占用一个字节进行编码,包括字段编号和字段类型(您可以在协议缓冲区编码中找到更多相关信息)。16到2047范围内的字段编号占用两个字节。因此,您应该为非常频繁出现的消息元素保留数字1到15。可以为将来可能添加的频繁出现的元素留出一些空间(可以这么理解吧,必填字段用1~15,选填字段使用16~2047)。
不能使用数字19000到19999,因为它们是为Protocol Buffers实现保留的。同样,也不能使用任何以前保留的字段编号。
保留字段
保留字段存在的必要性:如果只通过注释或删除字段来更新消息类型,可能导致删除或注释的字段被复用,从而使用新的消息类型解析已有的消息时,会带来困惑。
确保不会发生这种情况的一种方法是指定已删除字段的字段编号、名称(之所以保留名称,是担心JSON序列化的问题),如果任何未来的用户尝试使用这些字段标识符,协议缓冲区编译器会报错。
|
|
不可以在同一个reserved中混合使用字段名称和字段编号。
默认值
解析消息时,如果编码的消息不包含特定的singular元素(不是很理解这个前提),则解析对象中的相应字段将设置为该字段的默认值。这些默认值是特定于类型的:
- 对于字符串,默认值为空字符串。
- 对于字节,默认值为空字节。
- 对于bool,默认值为false。
- 对于数字类型,默认值为零。
- 对于enums,默认值是第一个定义的enum value,它必须是 0。
- 对于消息字段,未设置该字段。它的确切值取决于语言。有关详细信息,请参阅生成的代码指南。
- 重复字段的默认值为空(通常是相应语言的空列表)。
请注意,对于标量消息字段,一旦消息被解析,就无法判断字段是否明确设置为默认值(例如,布尔值是否设置为false)或根本没有设置:您应该记住这一点在定义消息类型时。例如,false如果您不希望默认情况下也发生该行为,则不要设置一个布尔值来开启某些行为。还要注意的是,如果一个标消息字段被设置为默认值,该值将不会在电线上连载。
有关默认值如何在生成的代码中工作的更多详细信息,请参阅所选语言的生成代码指南。
枚举类型
每个枚举定义都必须包含一个零的常量作为其第一个元素,这是因为:
- 必须有一个零值,以便我们可以使用0作为数字默认值
- 零值需要是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值
需要注意的事项:
- 枚举常量必须在32位整数范围内。
- 由于enum值在线路上使用varint编码,负值效率低下,因此不推荐使用。
- 可以在消息类型内部或者消息外部定义枚举,这些枚举当前proto文件中的任何消息类型复用。
- 可以使用_MessageType_._EnumType_使用其他消息内部定义的枚举。
不是很理解的知识
在反序列化期间,无法识别的枚举值将保留在消息中,尽管在反序列化消息时如何表示取决于语言。在支持值超出指定符号范围的开放枚举类型的语言(例如 C++ 和 Go)中,未知枚举值只是作为其底层整数表示存储。在 Java 等具有封闭枚举类型的语言中,枚举中的 case 用于表示无法识别的值,并且可以使用特殊访问器访问底层整数。在任何一种情况下,如果消息被序列化,无法识别的值仍将与消息一起序列化。
使用其他消息类型作为字段类型
很好理解,看代码:
|
|
嵌套类型
代码如下:
|
|
要在其父消息类型之外重用此消息类型,类似如下代码:
|
|
嵌套消息没有层数限制:
|
|
未知字段
未知字段是格式良好的协议缓冲区序列化数据,表示解析器无法识别的字段。例如,当旧二进制文件用新字段解析新二进制文件发送的数据时,这些新字段将成为旧二进制文件中的未知字段。
最初,proto3消息在解析过程中总是丢弃未知字段,但在 3.5 版本中,我们重新引入了未知字段的保留以匹配 proto2 行为。在 3.5 及更高版本中,未知字段在解析过程中保留并包含在序列化输出中。