【问题标题】:What's the preferred way to encode a "nullable" field in protobuf 2?在 protobuf 2 中编码“可为空”字段的首选方法是什么?
【发布时间】:2012-02-07 21:26:10
【问题描述】:

我正在定义一个 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 中存储可为空的字段的?

【问题讨论】:

标签: protocol-buffers


【解决方案1】:

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

此功能是“免费”提供的,因为字段在消息中使用“标签”进行编码。未设置的字段在编码消息中只是“不存在”。

Proto 3 does not have this feature,而是将任何缺失的字段设置为its default value

【讨论】:

  • 你确定吗?特别是,如果我对消息进行编码并通过网络发送它,我是否能够将其字段明确设置为默认值的对象与字段从未设置为任何值的对象区分开来?请参阅我的相关问题:stackoverflow.com/questions/9168052/…
  • 是的。您应该阅读有关如何编码 protobuf 消息的信息:code.google.com/apis/protocolbuffers/docs/encoding.html。消息被编码为一系列键/值对(这就是每个字段上的标识符/标签的用途)。编码消息中根本不存在未设置的字段。如果您有三个字段 a、b 和 c,标签分别为 1、2 和 3,并且您对一条消息进行编码,仅将“a”设置为“42”,那么编码后的消息将包含“field(1) = 42 英寸,仅此而已。
  • JesperE 的回答在过去可能是正确的,但现在绝对不再正确了。
【解决方案2】:

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

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

【讨论】:

  • 这只有在类型的域中有一些无意义的值时才有效。例如,对于坐标,-1 是一个完全有效的值。 “float”域内没有任何值不能是真正的坐标。
猜你喜欢
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-31
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多