为什么在协议缓冲区3中删除了required和optional

我最近在使用gRPCproto3,我注意到requiredoptional在新语法中被删除了。

有人能解释一下为什么在proto3中required/optional被删除了吗?这样的约束似乎是使定义健壮的必要条件。

语法proto2:

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

语法proto3:

syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
155870 次浏览

required的有用性一直是许多争论和火药战的核心。双方都有大型营地。一个阵营喜欢保证值的存在,并愿意接受它的局限性,但另一个阵营认为required危险或没有帮助,因为它不能安全地添加或删除。

让我解释一下为什么required字段应该谨慎使用的原因。如果你已经在使用一个原型,你不能添加一个必需的字段,因为旧的应用程序不会提供这个字段,而且应用程序通常不能很好地处理故障。你可以确保所有旧的应用程序都先升级,但是很容易犯错误,如果你把protos存储在任何数据存储中(即使是短期的,比如memcached)也没有帮助。同样的情况也适用于删除必填字段。

许多必填项“显然”是必须的,直到……他们没有。假设你有一个id字段用于Get方法。这是很明显必需的。除非,以后你可能需要将id从int改为string,或将int32改为int64。这需要添加一个新的muchBetterId字段,现在你剩下的是旧的id字段,必须被指定,但最终完全被忽略。

当这两个问题结合在一起时,有益的required字段的数量变得有限,阵营争论它是否仍然有价值。required的反对者不一定反对这个想法,但它目前的形式。一些人建议开发一个更有表现力的验证库,可以检查required和更高级的东西,如name.length > 10,同时也确保有一个更好的失败模型。

Proto3总体上似乎更倾向于简单,而required的删除更简单。但也许更令人信服的是,当与其他特性结合使用时,删除required对proto3是有意义的,比如删除原语的字段存在和删除覆盖默认值。

我不是一个protobuf开发人员,也不是这个主题的权威,但我仍然希望这个解释是有用的。

你可以在protobuf Github问题中找到解释:

我们在proto3中删除了必填字段,因为必填字段通常被认为是有害的,并且违反了protobuf的兼容性语义。使用protobuf的整个思想是,它允许您从协议定义中添加/删除字段,同时仍然与新/旧二进制文件完全向前/向后兼容。但必填字段打破了这一点。您永远不能安全地将必填字段添加到.proto定义中,也不能安全地删除现有的必填字段,因为这两种操作都会破坏连线兼容性。例如,如果您向.proto定义中添加了一个必填字段,那么使用新定义构建的二进制文件将无法解析使用旧定义序列化的数据,因为旧数据中不存在必填字段。在一个复杂的系统中,.proto定义在系统的许多不同组件之间广泛共享,添加/删除所需的字段很容易使系统的多个部分崩溃。我们已经多次看到由此导致的生产问题,并且在谷歌中几乎禁止任何人添加/删除必选字段。出于这个原因,我们在proto3中完全删除了必填字段。

删除“;required&;;optional&;”只是多余,所以我们删除了“可选”;也

可选字段在protobuf 3.15中返回

因为相关概念的正交分解是困难的,协议缓冲区设计以一种令人沮丧的方式组合了至少4个独立的概念:可空性(也就是存在跟踪)、内容验证、有用的默认值和空间效率。

Proto2允许一个字段为要么 'required'或'optional',并允许指定默认值,但只有为'optional'字段。

'optional'关键字在3.12/3.15中返回,用于在线状态跟踪。 看到现场存在的应用程序说明。< / p >

“required”关键字被应用为验证检查,这很不幸,因为Protobuf不能胜任作为验证工具的任务。它没有最小/最大值语法、长度或模式限制。更重要的是,它没有用于表示字段之间的数据值依赖关系(除了基本结构固有的关系)。

Protobuf使用初始构造值而且的“默认”值作为一种机制,通过不发送这些值来减少消息的大小(在proto3中)。这有点不幸,因为能够为特定的代码生成运行指定一个初始值对生产者(“这是我想在正常使用中发送的值”)或消费者(“也许我应该检查null/不存在,但返回,就像发送'x'一样就足够了__abc1 &;)都很方便。

OTOH,如果没有提供一个值,指定一个合同默认假设对如何继续进行似乎是有帮助的。然而,完成的工作通常取决于其他字段的值(或存在),而Protobuf由于同样(可以说很漂亮)缺乏复杂性而不能胜任这一点,这使得它不适合进行数据验证。因此,如果您希望在缺少字段时表现良好,最好将显式存在检查与任何其他合适的数据检查结合起来. ....至少在3.12/3.15以后,你可以. ...对于简单的情况,0值已经足够好了。