我最近用gRPC和proto3一起使用,我注意到required和optional在新语法中被删除了。

有人能解释一下为什么在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;
}

当前回答

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

Let me explain more of the reasoning why required fields should be used sparingly. If you are already using a proto, you can't add a required field because old application's won't be providing that field and applications in general don't handle the failure well. You can make sure that all old applications are upgraded first, but it can be easy to make a mistake and it doesn't help if you are storing the protos in any datastore (even short-lived, like memcached). The same sort of situation applies when removing a required field.

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

当这两个问题结合在一起时,有益的必填项的数量就会变得有限,阵营就会争论它是否仍然有价值。required的反对者并不一定是反对这个想法,而是反对它现在的形式。一些人建议开发一个更具表现力的验证库,可以与更高级的东西(如名称)一起检查所需。长度> 10,同时确保有一个更好的失败模型。

《Proto3》似乎更倾向于简单性,所需的移除也更简单。但也许更令人信服的是,当与其他功能结合在一起时,删除required对proto3是有意义的,比如删除原语的字段存在,删除覆盖默认值。

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

其他回答

可选字段在protobuf 3.15中返回

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

Proto2允许一个字段是“必需的”或“可选的”,并允许指定默认值,但仅限于“可选的”字段。

'optional'关键字在3.12/3.15中返回,用于在线状态跟踪。 请参阅应用程序的现场现场说明。

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

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

OTOH, it does seem like it would be helpful to specify a contractual default assumption for how to proceed if a value is not supplied. However, doing a good job of that often depends on the values(or presence) of other fields and Protobuf isn't up to that for the same (arguably beautiful) lack of complexity that makes it unsuitable for data validation. So if you want good behavior in the face of missing fields, you are best off combining explicit presence checks with whatever other data checks are appropriate. .... and at least in 3.12/3.15 onward you can. ... and maybe 0-ish values are good enough for the simplistic cases.

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

Let me explain more of the reasoning why required fields should be used sparingly. If you are already using a proto, you can't add a required field because old application's won't be providing that field and applications in general don't handle the failure well. You can make sure that all old applications are upgraded first, but it can be easy to make a mistake and it doesn't help if you are storing the protos in any datastore (even short-lived, like memcached). The same sort of situation applies when removing a required field.

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

当这两个问题结合在一起时,有益的必填项的数量就会变得有限,阵营就会争论它是否仍然有价值。required的反对者并不一定是反对这个想法,而是反对它现在的形式。一些人建议开发一个更具表现力的验证库,可以与更高级的东西(如名称)一起检查所需。长度> 10,同时确保有一个更好的失败模型。

《Proto3》似乎更倾向于简单性,所需的移除也更简单。但也许更令人信服的是,当与其他功能结合在一起时,删除required对proto3是有意义的,比如删除原语的字段存在,删除覆盖默认值。

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

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

We dropped required fields in proto3 because required fields are generally considered harmful and violating protobuf's compatibility semantics. The whole idea of using protobuf is that it allows you to add/remove fields from your protocol definition while still being fully forward/backward compatible with newer/older binaries. Required fields break this though. You can never safely add a required field to a .proto definition, nor can you safely remove an existing required field because both of these actions break wire compatibility. For example, if you add a required field to a .proto definition, binaries built with the new definition won't be able to parse data serialized using the old definition because the required field is not present in old data. In a complex system where .proto definitions are shared widely across many different components of the system, adding/removing required fields could easily bring down multiple parts of the system. We have seen production issues caused by this multiple times and it's pretty much banned everywhere inside Google for anyone to add/remove required fields. For this reason we completely removed required fields in proto3. After the removal of "required", "optional" is just redundant so we removed "optional" as well.