Protobuf中的Oneof和Enum有什么区别?

11
使用枚举和使用protobuf3中的oneof类型有什么区别?据我所知,枚举将字段限制为预定义的一组值之一,而oneof类型也是如此。
1个回答

4

枚举是具有名称的数字。您在枚举定义中定义名称并为其分配值。枚举应始终具有值零,如果设置了它。

enum State {
  A = 0;
  B = 1;
  C = 2;
}

下一步,您可以在任何消息中使用此枚举。
message Update {
  State currentState = 1;
  State previousState = 2;
}

oneof是一种非常不同的东西。它允许您发送不同类型的数据,但仅为它们分配有限的内存空间,因为您每次只能设置其中一种类型。这类似于C/C++中的union或C++17中的std::variant。

以这个例子为例,在我们的oneof中定义了一个消息、一个整数和一个双精度浮点数。

// The message in our oneof
message someMsg {
  // Multiple fields
}

// The message holding our oneof
message msgWithOneof {

  oneof theOneof {
    someMsg msg     = 1;
    int32   counter = 2;
    double  value   = 3;
  }
  // Feel free to add more fields her of before the oneof
}

您只能同时设置msgcountervalue中的一个。如果您设置另一个字段,这将清除其他字段。
假设采用C/C++实现,最大的字段将决定分配的内存量。例如,如果someMsg最大,则设置整数或双精度浮点数不会有问题,因为它们可以放在相同的空间中。如果您不使用oneof,则分配的总内存将是sizeof(someMsg) + sizeof(int32) + sizeof(double)的总和。
需要额外开销来跟踪已设置的字段。在Google的C++实现中,这是存在变量中的一位。这类似于标记为可选的字段。

2
在“不同类型”的基础上,它还允许您表示相同的类型,但具有不同的语义含义 - 例如,msgWithOneof.theOneof也可以有一个额外的double valueDelta = 4;someMsg criticialMessage = 5;(但在任何时候,theOneof中的值最多只能有一个值)。 - Marc Gravell
@MarcGravell 很好的评论。在 oneof 中多次重复相同类型确实很有可能只分配一次内存。 - Bart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接