为啥 proto3 中没有自定义默认值?

Posted

技术标签:

【中文标题】为啥 proto3 中没有自定义默认值?【英文标题】:Why are there no custom default values in proto3?为什么 proto3 中没有自定义默认值? 【发布时间】:2015-10-19 19:40:06 【问题描述】:

proto2 版本的 Protocol Buffers 允许为消息元素指定默认值:

optional double scaling_factor = 3 [default = 1.0];

为什么这在 proto3 中不再可行?我认为这是一个巧妙的功能,无需编写任何包装代码即可在线路上节省额外的字节。

【问题讨论】:

【参考方案1】:

我的理解是,proto3 不再允许您检测字段存在并且不再支持非零默认值,因为这样可以更容易地以各种语言的“普通旧结构”来实现 protobuf,而无需生成访问器方法。这被认为使 Protobuf 在这些语言中更易于使用。

(我个人认为缺少访问器和属性的语言不是很好的语言,protobuf 不应该设计到它们,但它不再是我的项目了。)

【讨论】:

似乎很遗憾,他们不能简单地检测线路上的现场存在并在丢失时应用合同默认值。这本身应该与语言无关。 @MeirionHughes - 我相信问题出现在实例化一个新对象时,而不是离线。如果您的语言没有提供构造函数的概念和访问器的概念,那么您就无法将字段初始化为默认值,而与序列化无关。 但是你肯定可以在构造后简单地分配结构字段吗?我想不出任何合理的理由为什么你会有一种定义不可初始化、不可变结构的语言...... @MeirionHughes 当然可以,但默认值的全部意义在于它应该自动设置。如果没有构造函数,则无法在应用程序代码中分配对象时自动初始化它;应用程序代码作者总是需要手动调用一些初始化函数。人们很可能会忘记。 打破向后兼容性以使您免于在某些语言中使用对象工厂似乎很奇怪......即使如此,“默认”指令是一项合同功能;因为它只与电汇有关。如果 POCO 对象字段与合同默认值不同,那么这些字段只会被发送出去。看到您总是使用库进行反序列化,缺少的字段可以很容易地由库本身初始化为合约默认值。无论如何,我将停止向比我更了解这一点的人讲道。:P【参考方案2】:

这是一种解决方法,而不是直接回答您的问题,但我发现自己使用 wrappers.proto 可选值,然后当我绝对必须知道这是默认值还是显式设置的值。

您的代码必须强制执行该值而不是生成的代码本身并不是最优的,但如果您拥有双方,至少它是一个可行的替代方案,而不是不知道该值是默认值还是显式设置,尤其是当查看设置为 false 的布尔值时。

我不清楚这会如何影响线路上的字节。对于我使用它的实例,消息长度不是设计约束。

原始文件

import "google/protobuf/wrappers.proto";

google.protobuf.BoolValue optional_bool = 1;

Java 代码

//load or receive message here
if( !message.hasOptionalBool() )
    message.setOptionalBool( BoolValue.newBuilder().setValue( true ) );

【讨论】:

工作谢谢!!!!添加到将 Bool 转换为 *wrapper.Bool 的答案。执行这些步骤 1. import "github.com/golang/protobuf/ptypes/wrappers" 2. 转换 &wrappers.BoolValueValue:v.PkgIsEnabled 【参考方案3】:

在我的自动生成文件 .pb.cc 中,我看到很少有这样的地方:

if (this->myint() != 0) 

很少有这样的:

myint_ = 0;

那么,为什么不启用默认值并生成

static ::google::protobuf::int32 myint_defaultvalue = 5;

...
if (this->myint() != myint_defaultvalue) 
...

...
myint_ = myint_defaultvalue;
...

改为?

【讨论】:

以上是关于为啥 proto3 中没有自定义默认值?的主要内容,如果未能解决你的问题,请参考以下文章

Go

vs2008时间控件设置默认值

为啥自定义表格单元格总是默认大小

proto 3 中的可选(重复)字段

为啥IE的安全级别修改不了?

为啥在自定义 WinRT C++/CX 控件中默认添加 [Windows::Foundation::Metadata::WebHostHidden]?