protobuf里有枚举类型,定义如下
enum PhoneType
{
string home_addr = 0;
string work_addr = 1;
}
同message
一样,可分为 嵌套定义,文件内定义,文件外定义。不过多演示
但是值得注意的点是
enum A
{
int32 a = 0;
}
enum B
{
int32 a = 0;
}
A和B有相同的变量a,所以会报错
enum A
{
int32 a = 0;
}
message C
{
enum B
{
int32 a = 0;
}
}
// 在 A.proto 文件里
import "B.proto"
enum A
{
int32 a = 0; // 报错,B.proto 里以及定义
}
-----------------------
// 在 B.proto 文件里
enum B
{
int32 a = 0;
}
// 在 A.proto 文件里
import "B.proto"
package A;
enum A
{
int32 a = 0;
}
-----------------------
// 在 B.proto 文件里
package B;
enum B
{
int32 a = 0;
}
介绍一下ANY类型,ANY类型表示任意类型
如何将其引入 .proto 文件里
// 在/usr/local/protobuf/include
import "google/protobuf/any.proto";
// 使用
message Any{
google.protobuf.Any data = 1;
}
// 已知信息如下
/ contacts.proto文件 //
syntax = "proto3"
package contacts;
import "google/protobuf/any.proto"; // 引入Any类型
message PeopleInfo
{
// 可以用于任何类型的any
google.protobuf.Any data = 1;
}
message Address
{
string home_addr;
}
test.cc文件 //
#include
#include "contacts.pb.h" // contacts.proto 编译后生成的头文件
using namespace std;
int main()
{
// 包装
contact2::PeopleInfo people;
contact2::Address addr;
addr.set_home_addr("中国");
google::protobuf::Any* any = people.mutable_data(); // 开辟一段any对象的空间
any->PackFrom(addr); // 将addr打包成Any类型
// 转换
contact2::Address addr2;
if(people.has_data())
{
google::protobuf::Any any = people.data(); // 获取people里的Any类对象
if(any.Is<contact2::Address>()) // 判断any类型是否为 Address 类
{
any.UnpackTo(&addr2); // 输出型参数,填充add2
cout << addr2.home_addr() << endl; // 打印
}
}
return 0;
}
编译 .proto 文件,然后编译连接 test.cc 文件,执行结果如下:
oneof 类型语法简单:
message PeopleInfo
{
string name = 1;
oneof gender
{
string male = 2;
string female = 3;
}
}
但是值得注意的点是
看看编译后的 .pb.h 文件里定义的内容
class PeopleInfo final :
public ::PROTOBUF_NAMESPACE_ID::Message
{
enum GenderCase
{
kMale = 2,
kFemale = 3,
GENDER_NOT_SET = 0,
};
// string male = 2;
bool has_male() const;
void clear_male();
const std::string& male() const;
template <typename ArgT0 = const std::string&, typename... ArgT>
void set_male(ArgT0&& arg0, ArgT... args);
std::string* mutable_male();
PROTOBUF_NODISCARD std::string* release_male();
void set_allocated_male(std::string* male);
// string female = 3;
bool has_female() const;
void clear_female();
const std::string& female() const;
template <typename ArgT0 = const std::string&, typename... ArgT>
void set_female(ArgT0&& arg0, ArgT... args);
std::string* mutable_female();
PROTOBUF_NODISCARD std::string* release_female();
void set_allocated_female(std::string* female);
void clear_gender();
GenderCase gender_case() const;
}
会将 oneof 中的多个字段定义为⼀个枚举类型。
类似于C++里面的 map 类型,protobuf自己实现了一个类似的数据结构,protobuf 的 map 类型的实现是基于它的 Message 类型的。
message PeopleInfo
{
map<string, string> info = 1;
}
但是值得注意的点是
repeatedmap< key_type, value_type> map_name = N;
讲解一下几个相关常用函数
Map< std::string, std::string >*mutable_info()
void clear_info();
清空对象里的内容。此外,map还支持迭代器,和C++里的 unorderedmap 十分类似。
运用上述知识点,对上一篇的通讯录代码进行增添功能
contacts.proto
syntax = "proto3";
package contact2;
// 在/usr/local/protobuf/include
import "google/protobuf/any.proto";
// 地址信息
message Address
{
string home_addr = 1;
string work_addr = 2;
}
// 个人信息
message PeopleInfo
{
string name = 1;
int32 age = 2;
// 嵌套定义
message Phone{
string number = 1;
// 嵌套枚举
enum PhoneType{
MP = 0; // 移动电话
TEL = 1; // 固定电话
}
PhoneType type = 2;
}
// repeated 修饰词 修饰的变量相当于数组
repeated Phone phone = 3;
google.protobuf.Any data = 4;
// 其他联系方式
oneof other_contacts
{
string QQ = 5;
string Wechat = 6;
}
// 备注
map<string, string> remark = 7;
}
// 通讯录
message Contacts
{
repeated PeopleInfo contacts = 1;
}
执行结果
read.cpp