协议缓冲区 - 唯一编号标记 - 澄清?

时间:2014-11-09 08:25:49

标签: protocol-buffers

我正在使用协议缓冲区,一切正常。除了我不理解的事实 - 为什么我需要proto文件中的编号标签:

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}

当然,我已经阅读了docs

  

如您所见,消息定义中的每个字段都具有唯一性   编号标签。这些标签用于标识您的字段   消息二进制格式,一旦消息不应更改   类型正在使用中。

我不明白如果我改变它会有什么不同。 (我将创建一个新的原型并编译它 - 所以它为什么关心?)

Another article states that :

  

原型定义中的编号字段消除了对版本的需求   检查哪些是明确说明的动机之一   协议缓冲区的设计和实现。作为开发人员   文档说明,协议的设计部分是为了避免“丑陋”   代码“像这样检查协议版本:

if (version == 3) {
  ...
} else if (version > 4) {
  if (version == 5) {
    ...
  }
  ...
}

问题

只是我还是完全不清楚?

让我以不同的方式提出这个问题:

如果我有一个类似上述文件的proto文件,那么我将其更改为:

message SearchRequest {
  required string query = 3; //reversed order
  optional int32 page_number = 2;
  optional int32 result_per_page = 1;
}

它在乎什么?我重新编译并添加文件(我在上周已多次完成)。

我错过了什么?你能为这个编号的标签提供人对人的解释吗?

2 个答案:

答案 0 :(得分:23)

编号标签用于在序列化和反序列化数据时匹配字段。

显然,如果更改编号方案,并将此更改应用于序列化器和反序列化器,则没有问题。

但请注意,如果您使用第一个编号方案保存数据,并使用第二个编号方案加载它,则会尝试将query加载到result_per_page,反序列化可能会失败。

现在,为什么这有用? 我们假设您需要在数据中添加另一个字段,很久就会使用该模式:

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
  optional int32 new_data = 4;
}

因为您明确地给它一个数字,所以您的反序列化程序仍然能够加载使用编号方案序列化的数据,而忽略了对不存在的数据进行反序列化。

答案 1 :(得分:3)

这些字段编号在编码和解码时由protobuf使用。有关详细信息,请参阅here

因此每个字段都有线型,因此int32的线型为0,字段编号为2,因此它将被编码为0001 0000,即十进制为10。

稍后当它被解码时,它的左移1,这使得它成为001 0000,最后三个lsb决定导线类型,即它然后输出int类型的字段,其余决定原型中的哪个字段即00010是2.因此,电线类型0(int)的字段2