我正在定义一个ProtoBuf消息,我想要一个“可空”字段 - 即,我想要区分具有值且没有值的字段。举一个具体的例子,假设我有“x”和“y”字段来记录某个对象的坐标。但在某些情况下,坐标是未知的。以下定义不有效,因为如果未指定x或y,则它们默认为零(这是一个有效值):
message MyObject {
optional float x = 1;
optional float y = 2;
}
一个选项是添加一个布尔字段,记录相应字段的值是否已知。即:
message MyObject {
optional bool has_x = 1; // if false, then x is unknown.
optional bool has_y = 2; // if false, then y is unknown.
optional float x = 3; // should only be set if has_x==true.
optional float y = 4; // should only be set if has_y==true.
}
但是这会增加一些额外的簿记 - 例如,当我设置x字段的值时,我必须始终记住也设置has_x。另一种选择是使用列表值,其中列表总是具有长度0或长度1:
message MyObject {
repeated float x = 1; // should be empty or have exactly 1 element.
repeated float y = 2; // should be empty or have exactly 1 element.
}
但在这种情况下,定义似乎有点误导,界面也不是更好。
有没有第三种选择,我没有想到这比这两种更好?你是如何处理在protobuf中存储可空字段的?
答案 0 :(得分:4)
Protobuf 2消息具有“可空字段”的内置概念。 C ++接口包含方法has_xxx
和clear_xxx
,分别检查字段是否已设置并取消设置字段。
由于使用“标签”在消息中编码字段的方式,此功能“免费”。未设置的字段在编码消息中简单地“不存在”。
Proto 3 does not have this feature,而是将任何缺少的字段设置为its default value。
答案 1 :(得分:1)
对每种类型都有NaN
的概念,然后使用default
(如下所示)将其设置为值。如果没有为该特定字段指定任何内容,则将使用此方法。
optional float x = 1 [default = -1];