Protobuf 必需字段和默认值

6
我是protobuf的新手,我已开始考虑以下微不足道的例子。
message Entry {
  required int32 id = 1;
}

被C++代码使用

#include <iostream>
#include "example.pb.h"
int main() {
  std::string mySerialized;
  {
    Entry myEntry;
    std::cout << "Serialization succesfull " 
              << myEntry.SerializeToString(&mySerialized) << std::endl;
    std::cout << mySerialized.size() << std::endl;
  }
  Entry myEntry;
  std::cout << "Deserialization successfull "
            << myEntry.ParseFromString(mySerialized) << std::endl;
}

即使“id”字段是必需的,但由于未设置它,序列化缓冲区的大小为0(??)。
当我反序列化消息时,发生错误:
[libprotobuf ERROR google/protobuf/message_lite.cc:123] Can't parse message of type "Entry" because it is missing required fields: id

这是正常的行为吗?

Francesco

附言- 如果我将"id"初始化为0,行为会有所不同

附言2- SerializeToString 函数返回true,ParseFromString 函数返回false


这些方法难道没有返回值告诉你它们是否成功了吗?你有检查过它们吗? - Marc Gravell
请注意,在protobuf中,零长度缓冲区是完全有效的——如果没有要序列化的字段,那就是你得到的结果。 - Marc Gravell
1个回答

5
我不确定我是否完全理解了你的问题,但我会尝试回答。希望这能在某种程度上对你有所帮助 :)
是的,这是正常行为。只有当字段对消息很重要时,才应该添加“required”。从语义上讲,这是有意义的(为什么要跳过必填字段)。为了强制执行此规则,protobuf 将不会解析该消息。
它看到标记为 1 的字段是必需的,并且“has_id()”方法返回 false。因此,它根本不会解析该消息。
开发人员指南中,建议不要使用 required 字段。
引用如下: Required Is Forever:您应该非常谨慎地将字段标记为必需的。如果某个时刻您希望停止编写或发送必需字段,则将更改该字段为可选字段将会有问题——旧的读者将认为没有该字段的消息是不完整的,并可能无意中拒绝或删除它们。您应该考虑为缓冲区编写特定于应用程序的自定义验证例程。Google 的一些工程师得出结论,使用 required 会带来更多的伤害而不是好处;他们更喜欢仅使用 optional 和 repeated。然而,这种观点并不普遍。
此外,
引用如下:
任何新添加的字段都应该是可选或重复的。这意味着使用“旧”消息格式的代码序列化的任何消息都可以被您的新生成的代码解析,因为它们不会缺少任何必需元素。您应该为这些元素设置合理的默认值,以便新代码可以正确地与旧代码生成的消息进行交互。同样,由您的新代码创建的消息可以由您的旧代码解析:旧的二进制文件在解析时简单地忽略新字段。但是,未知字段不会被丢弃,如果稍后序列化该消息,则未知字段将与其一起序列化——因此,如果将消息传递给新代码,则新字段仍然可用。请注意,当前无法保留 Python 的未知字段。

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