313

我最近在使用gRPCwith proto3,并且我注意到了这一点,required并且optional已在新语法中被删除。

有人能解释一下为什么在 proto3 中删除了必需/可选的吗?这种约束似乎只是使定义稳健所必需的。

语法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;
}
4

3 回答 3

530

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

required让我解释一下为什么应该谨慎使用字段的原因。如果您已经在使用原型,则无法添加必填字段,因为旧应用程序不会提供该字段,并且应用程序通常不能很好地处理故障。您可以确保首先升级所有旧应用程序,但是很容易出错,并且如果您将 protos 存储在任何数据存储中(即使是短暂的,例如 memcached)也无济于事。删除必填字段时也适用同样的情况。

许多必填字段“显然”是必需的,直到……它们不是。假设您有一个方法id字段Get。这显然是必需的。除了,稍后您可能需要将idint 更改为 string,或将 int32 更改为 int64。这需要添加一个新muchBetterId字段,现在您只剩下必须id指定的旧字段,但最终会被完全忽略。

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

Proto3 总体上似乎更倾向于简单,required移除更简单。但也许更有说服力,required当与其他功能结合使用时,删除对于 proto3 是有意义的,例如删除原语的字段存在和删除覆盖的默认值。

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

于 2015-08-04T16:49:45.750 回答
70

你可以在这个protobuf Github issue中找到解释:

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

在删除“必需”之后,“可选”只是多余的,所以我们也删除了“可选”。

于 2018-09-17T02:56:05.617 回答
13

protobuf 3.15 中返回了可选字段

于 2021-03-17T13:10:23.200 回答