2013-03-12 329 views
5

我是新来的protobuf和我已经开始考虑下面简单的例子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-如果我初始化 “ID” 值为0,该行为是不同的

PPS-的SerializeToString函数返回true,则ParseFromString返回false

+0

请不要这些方法有返回值来告诉您它是否有效吗?你在检查他们吗? – 2013-03-12 11:22:08

+0

请注意,零长度缓冲区在protobuf中是完全有效的 - 如果没有要序列化的字段 – 2013-03-12 12:07:51

回答

4

我不认为我完全理解你的问题,但无论如何我都会接受答案。希望这可以帮助你以某种方式或其他:)

是的这是正常的行为。只有在该字段对消息很重要时,您才应添加required。它在语义上很有意义。 (为什么你会跳过一个必填字段)。为了执行此操作,protobuf不会分析消息。

它看到标有数字1的字段是必需的,并且has_id()方法返回false。所以它不会解析信息。

developer guide建议不要使用必填字段。

必填永远您应该非常小心地根据需要标记字段。如果您希望在某个时候停止撰写或发送必填字段,将字段更改为可选字段会有问题 - 旧读者会认为没有此字段的邮件不完整,可能会无意中拒绝或放弃邮件。您应该考虑为您的缓冲区编写特定于应用程序的自定义验证例程。 Google的一些工程师已经得出结论:使用所需要的不仅仅是好处而已,他们更喜欢只使用可选的和重复的。但是,这种观点并不普遍。

而且

您添加应选配或重复任何新的领域。这意味着任何由代码使用“旧”消息格式进行序列化的消息都可以通过新生成的代码进行分析,因为它们不会丢失任何必需的元素。您应该为这些元素设置合理的默认值,以便新代码可以正确地与旧代码生成的消息进行交互。同样,由新代码创建的消息可以由旧代码解析:旧的二进制文件在解析时会简单地忽略新字段。但是,未知字段不会被丢弃,并且如果稍后序列化消息,则未知字段将与其一起序列化 - 因此,如果消息传递给新代码,新字段仍然可用。请注意,保留未知字段目前不适用于Python