您可以根据需要深度嵌套消息:
message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 int64 ival = 1; bool booly = 2; } } message MiddleBB { // Level 1 message Inner { // Level 2 int32 ival = 1; bool booly = 2; } } } Updating A Message Type如果现有消息类型不再满足您的所有需求(例如,您希望消息格式具有一个额外的字段),但是您仍然希望使用以旧格式创建的代码,请不要担心!在不破坏任何现有代码的情况下更新消息类型非常简单。只要记住以下规则:
不要更改任何现有字段的字段编号。
如果添加新字段,则仍可以使用新生成的代码来解析使用“旧”消息格式通过代码序列化的任何消息。您应该记住这些元素的默认值,以便新代码可以与旧代码生成的消息正确交互。同样,由新代码创建的消息可以由旧代码解析:旧的二进制文件在解析时只会忽略新字段。有关详细信息,请参见“未知字段”部分。
只要在更新的消息类型中不再使用字段号,就可以删除字段。您可能想要重命名该字段,或者添加前缀“ OBSOLETE_”,或者保留该字段编号,以使.proto的将来用户不会意外重用该编号。
int32,uint32,int64,uint64和bool都是兼容的–这意味着您可以将字段从这些类型中的一种更改为另一种,而不会破坏向前或向后的兼容性。如果从对应的类型不适合的导线中解析出一个数字,则将获得与在C ++中将数字强制转换为该类型一样的效果(例如,如果将64位数字读取为int32,它将被截断为32位)。
sint32和sint64彼此兼容,但与其他整数类型不兼容。
字符串和字节兼容,只要字节是有效的UTF-8。
如果字节包含消息的编码版本,则嵌入式消息与字节兼容。
fixed32与sfixed32兼容,fixed64与sfixed64兼容。
对于字符串,字节和消息字段,可选与重复兼容。给定重复字段的序列化数据作为输入,如果期望该字段是可选的,则如果它是原始类型字段,则将采用最后一个输入值;如果是消息类型字段,则将合并所有输入元素。请注意,这对于数字类型(包括布尔值和枚举)通常并不安全。重复的数字类型字段可以以打包格式序列化,当期望使用可选字段时,该格式将无法正确解析。
在有线格式方面,enum与int32,uint32,int64和uint64兼容(请注意,如果值不合适,该值将被截断)。但是请注意,客户端代码在反序列化消息时可能会以不同的方式对待它们:例如,无法识别的proto3枚举类型将保留在消息中,但是反序列化消息时如何表示这取决于语言。 Int字段始终只是保留其值。
将单个值更改为新的oneof的成员是安全且二进制兼容的。如果您确定一次没有代码设置多个字段,那么将多个字段移动到一个新字段中可能是安全的。将任何字段移至现有字段都不安全。
Unknown Fields未知字段是格式正确的协议缓冲区序列化数据,表示解析器无法识别的字段。 例如,当旧的二进制文件使用新字段解析新二进制文件发送的数据时,这些新字段将成为旧二进制文件中的未知字段。
最初,proto3消息在解析过程中总是丢弃未知字段,但是在版本3.5中,我们重新引入了保留未知字段以匹配proto2行为的功能。 在版本3.5和更高版本中,未知字段将在解析期间保留并包含在序列化输出中。
AnyAny消息类型使您可以将消息用作嵌入式类型,而无需定义它们的.proto。 Any包含任意序列化的消息(以字节为单位)以及URL,URL作为该消息的类型并解析为该消息的类型的全局唯一标识符。 要使用Any类型,您需要导入google / protobuf / any.proto。
import "google/protobuf/any.proto"; message ErrorStatus { string message = 1; repeated google.protobuf.Any details = 2; }给定消息类型的默认类型URL为type.googleapis.com/packagename.messagename。
不同的语言实现将支持运行时库帮助程序以类型安全的方式打包和解压缩Any值-例如,在Java中,Any类型将具有特殊的pack()和unpack()访问器,而在C ++中则具有PackFrom()和UnpackTo () 方法:
// Storing an arbitrary message type in Any. NetworkErrorDetails details = ...; ErrorStatus status; status.add_details()->PackFrom(details); // Reading an arbitrary message from Any. ErrorStatus status = ...; for (const Any& detail : status.details()) { if (detail.Is<NetworkErrorDetails>()) { NetworkErrorDetails network_error; detail.UnpackTo(&network_error); ... processing network_error ... } }当前,正在开发用于任何类型的运行时库。
如果您已经熟悉proto2语法,则Any可以保存任意proto3消息,类似于可以允许扩展的proto2消息。
Oneof