我是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
这是正常行为吗?
弗朗西斯
ps-如果我使用值0初始化“id”,则行为是不同的
pps- SerializeToString
函数返回true,ParseFromString
返回false
答案 0 :(得分:4)
我不认为我完全理解你的问题,但无论如何我都会找到答案。希望这能以某种方式帮助你:)
是的,这是正常行为。仅当字段对邮件很重要时,才应添加required
。它在语义上是有道理的。 (为什么你会跳过必填字段)。为了强制执行此操作,protobuf不会解析该消息。
它看到标有数字1的字段是必需的,has_id()
方法返回false。所以它根本不解析这个消息。
在developer guide中,建议不要使用必填字段。
永远需要您应该非常小心地根据需要标记字段。如果您希望在某个时刻停止写入或发送必填字段,则将字段更改为可选字段会有问题 - 旧读者会认为没有此字段的邮件不完整,可能会无意中拒绝或丢弃它们。您应该考虑为缓冲区编写特定于应用程序的自定义验证例程。谷歌的一些工程师得出的结论是,使用必需品弊大于利;他们更喜欢只使用可选和重复。但是,这种观点并不普遍。
另外
您添加的任何新字段都应该是可选的或重复的。这意味着使用“旧”消息格式的代码序列化的任何消息都可以由新生成的代码进行解析,因为它们不会缺少任何必需的元素。您应该为这些元素设置合理的默认值,以便新代码可以与旧代码生成的消息正确交互。同样,您的新代码创建的消息可以由旧代码解析:旧的二进制文件在解析时只是忽略新字段。但是,未丢弃未知字段,并且如果稍后序列化消息,则未知字段将与其一起序列化 - 因此,如果将消息传递给新代码,则新字段仍然可用。请注意,目前无法保存未知字段