一般,编写一个protocol buffers应用需要经历例如如下三步:数组
首先咱们可以经过Google在线文档上提供的一个电话簿的样例来了解下。只是略微加了点修改。
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
required bytes unsure = 5; //Add byte array here
}
message AddressBook {
repeated Person person = 1;
}
诚如你看到的同样,消息格式定义很是easy。对于每个字段而言都有一个修饰符(required/repeated/optional)、字段类型(bool/string/bytes/int32等)和字段标签(Tag)组成。
三个修饰符从词义上可以很是清楚的弄明确。
1)对于required的字段而言,初值是必须要提供的,不然字段的即是未初始化的。网络
在Debug模式的buffer库下编译的话,序列化话的时候可能会失败,而且在反序列化的时候对于该字段的解析会老是失败的。因此,对于修饰符为required的字段,请在序列化的时候务必给予初始化。函数
2)对于optional的字段而言,假设未进行初始化。那么一个默认值将赋予该字段。固然也可以指定默认值。如上述proto定义中的PhoneType字段类型。
3)对于repeated的字段而言,该字段可以反复多个,google提供的这个addressbook样例便有个很是好的该修饰符的应用场景,即每个人可能有多个电话号码。在高级语言里面,咱们可以经过数组来实现,而在proto定义文件里可以使用repeated来修饰,从而达到一样目的。固然。出现0次也是包括在内的。ui
当中字段标签标示了字段在二进制流中存放的位置,这个是必须的,而且序列化与反序列化的时候一样的字段的Tag值必须相应,不然反序列化会出现意想不到的问题。
google
3、编译proto文件。生成特定语言数据的数据定义代码 指针
经过查看头文件,可以发现针对每个字段都会大体生成例如如下几种函数,以number为例:
// required string number = 1;
inline bool has_number() const;
inline void clear_number();
inline const ::std::string& number() const;
inline void set_number(const ::std::string& value);
inline void set_number(const char* value);
inline ::std::string* mutable_number();
可以看出。对于每个字段会生成一个has函数(has_number)、clear清除函数(clear_number)、set函数(set_number)、get函数(number和mutable_number)。这儿解释下get函数中的两个函数的差异,对于原型为const std::string &number() const的get函数而言,返回的是常量字段,不能对其值进行改动。但是在有一些状况下,对字段进行改动是必要的。因此提供了一个mutable版的get函数,经过获取字段变量的指针,从而达到改变其值的目的。
而对于字段修饰符为repeated的字段生成的函数。则略微有一些不一样,如phone字段,则编译器会为其产生例如如下的代码:
// repeated .Person.PhoneNumber phone = 4;
inline int phone_size() const;
inline void clear_phone();
inline const ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >& phone() const;
inline ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >* mutable_phone();
inline const ::Person_PhoneNumber& phone(int index) const;
inline ::Person_PhoneNumber* mutable_phone(int index);
inline ::Person_PhoneNumber* add_phone();
可以看出,set函数变成了add函数,这个事实上很是好理解。code
上面也说过。repeated修饰的字段在高级语言中的实现多是个数组或动态数组,因此固然经过加入的方式来加入新的字段值。而起get函数也变化很是大。这个也不用多说了。
文档
好了。本文主要是对了解protocol buffer做了些简单的介绍,固然更具体的仍是看官方文档。get