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

Roy*_*mir 26 protocol-buffers

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

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}
Run Code Online (Sandbox Code Playgroud)

当然,我已经阅读了文档:

如您所见,消息定义中的每个字段都有一个唯一的编号标记.这些标记用于以消息二进制格式标识字段,并且在使用消息类型后不应更改.

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

另一篇文章指出:

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

if (version == 3) {
  ...
} else if (version > 4) {
  if (version == 5) {
    ...
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

它只是我还是完全不清楚?

让我以不同的方式问它:

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

message SearchRequest {
  required string query = 3; //reversed order
  optional int32 page_number = 2;
  optional int32 result_per_page = 1;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Rot*_*tem 30

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

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

考虑不过,如果你与第一编号方案保存的数据,并与第二个加载它,它会尝试加载queryresult_per_page,和反序列化可能会失败.

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

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
  optional int32 new_data = 4;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 现在它被理解了.他们如此难以举例说明吗? (4认同)
  • @almasshaikh 在一个简短的(15 行!)不能简单地以简短的方式解释它的情况下 - 这迫使我进入内部 - 我觉得这令人不安。 (2认同)

SMA*_*SMA 5

protobuf 在编码和解码时使用这些字段编号。请参阅此处了解更多详情。

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

稍后在解码时,它左移 1 使其成为 001 0000,最后三个 lsb 决定线类型,即它然后确定其类型为 int 字段,其余部分决定它是 proto 中的哪个字段,即 00010 是 2。所以导线类型 0 的字段 2 (int)