为什么Protobuf 3将消息上的所有字段都设为可选?


15

protobuf的语法3使所有字段成为可选字段,从而删除了关键字required以及optional以前的proto2语法。阅读开发人员的一些评论似乎是为了增强向前/向后二进制兼容性而完成的。

但是对我而言,这可以通过仅对软件包名称进行版本控制(例如说)com.example.messages.v1,然后让客户端实施他们理解的反序列化程序来实施。同时,它删除了一些从软件工程的角度来看有用的合同类型。例如,如果我有

message Location {
   double latitude = 1;
   double longitude = 2;
}

在proto3中,可以Location通过不提供必填字段之一来创建半备份但完全有效的文件。

创建基于模式的序列化格式以在客户端之间交换数据时,这不是一个很大的缺点吗?将额外的验证代码移至每个客户端以检查所有必填字段均具有有效值,这不是更糟吗?


Answers:


13

proto3进行了许多更改(据我所知),旨在使其在跨平台方案中更加有用。的“分配”与“不分配,但报告的默认值”,可以显式跟踪非常辛苦一些目标平台来实现,也可以混淆使用。因此,proto3采用了一种更为简单的方法:

  • 隐式默认值是天然零值(数字/枚举),假(布尔值)或空字符串(字符串)
  • 允许隐式默认值;不允许其他默认值
  • 如果字段具有该默认值,则不进行序列化;是否将其显式分配给零/假/空字符串与从未分配无关紧要
  • 因此,没有“必需”的概念,因为“明确分配了零值”和“从未分配过值”看起来是相同的

在proto3中,可以通过不提供必填字段之一来创建半备份但完全有效的位置。

另一个值为:零。您没有明确将其分配为零的事实是没有意义的。是否需要此操作取决于您,但这对我来说很有意义,并且是很多“初始化新对象/结构”在多种平台上如何工作的方式。

将额外的验证代码移至每个客户端以检查所有必填字段均具有有效值,这不是更糟吗?

没有什么可以验证的!如果显式分配了零值,则布局就是这样。如果那是合法的,那是合法的。如果它是非法的(因为零对您而言没有意义),则它是非法的;但无论是显式的还是隐式的,都是非法的。所涉及的验证量不会改变。

创建基于模式的序列化格式以在客户端之间交换数据时,这不是一个很大的缺点吗?

通常不,不...尤其是由于架构版本是显式的。如果要使用proto2,请使用proto2。什么都不会自动更改。


我想知道“只有默认的自然零”会买什么,因为如果没有某种模式,protobuf真的不可用。确保一致的默认设置听起来并不比首先确保一致的架构困难。
CodesInChaos

1
@CodesInChaos很有意思,因为我一直在protobuf-net中为...做无架构的protobuf,好吧,直到永远:),预计大多数用户将是代码优先和无架构的。有趣的是(至少对我来说)protobuf-net使用的大多数“保持简单,愚蠢”默认策略与proto3选择使用的策略完全相同。我不会声称这可以验证我的随机游击队决定,但是……完全可以做到:)
Marc Gravell

我认为C#类是一种架构,您当然可以通过属性指定默认值。将此与例如msgpack或json进行对比,后者可以创建有意义的数据结构,而无需任何模式。
CodesInChaos

@CodesInChaos同意并指出-是的,protobuf-net将遵守并遵守任何此类声明
Marc Gravell
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.