2012-02-07 222 views
3

我正在定义一个ProtoBuf消息,我想要一个“可空”字段 - 即,我想区分具有值和没有值的字段。作为一个具体的例子,假设我有“x”和“y”字段来记录某个对象的坐标。但在某些情况下,坐标未知。下面的定义将工作,因为如果x或y是不确定的,那么他们默认为零(这是一个有效的值):在protobuf中对“可空”字段进行编码的首选方法是什么?

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中存储可空字段?

回答

2

Protobuf消息具有“可空字段”的内置概念。 C++接口包含方法has_xxxclear_xxx,分别检查字段是否已设置并取消设置字段。

由于字段使用“标签”在邮件中编码的方式,此功能“免费”。未编码的字段在编码的消息中只是“不存在”。

+0

你确定吗?特别是,如果我编码一条消息并通过线路发送消息,我能够将其字段明确设置为默认值的对象与其字段从未设置为任何值的对象区分开来吗?看到我的相关问题:http://stackoverflow.com/questions/9168052/how-do-has-field-methods-relate-to-default-values-in-protobuf – 2012-02-08 16:29:51

+1

是的。您应该阅读如何编码protobuf邮件:http://code.google.com/apis/protocolbuffers/docs/encoding.html。消息被编码为一系列键/值对(这是每个字段上的标识符/标签的用途)。未编码的消息中没有未设置的字段。如果您有三个字段,分别为标签1,2和3的a,b和c,并且只对“a”设置为“42”编码消息,则编码消息将包含“field(1)= 42“,没有别的。 – JesperE 2012-02-09 07:29:52

+3

JesperE的回答在过去可能是真实的,但它绝对不是真的。 – jordanbtucker 2016-02-26 09:35:52

1

对于每种类型都有NaN的概念,然后使用default(如下所示)将其设置为值。如果没有为该特定字段指定任何内容,将会使用这个。

optional float x = 1 [default = -1]; 
+4

这只适用于类型的域内存在一些非有意义的值。例如,对于坐标,-1是完全有效的值。 “浮动”域内没有值不能成为真正的坐标。 – 2012-02-08 16:27:47

相关问题