【ProtoBuf 语法详解】map 类型

【ProtoBuf 语法详解】map 类型 文章目录1. map 类型2. 升级通讯录至 2.4 版本2.1 更新 contacts.proto 文件2.2 更新 write.cc 文件2.3 更新 read.cc 文件2.4 编译运行1. map 类型该语法支持创建一个关联映射字段也就是可以使用 map 类型去声明字段类型格式为mapkey_type, value_type map_field N;要注意的是key_type是除了 float 和 bytes 类型以外的任意标量类型。value_type可以是任意类型。map 字段不可以用 repeated 修饰。map 中存入的元素是无序的。2. 升级通讯录至 2.4 版本最后通讯录 2.4 版本想新增联系人的备注信息我们可以使用 map 类型的字段来存储备注信息。2.1 更新 contacts.proto 文件代码如下syntaxproto3;package contacts;// package 是一个可选的声明符, 声明其命名空间// 引入 any.proto 文件importgoogle/protobuf/any.proto;// 地址message Address{string home_address1;// 家庭地址string unit_address2;// 单位地址}// 定义联系人messagemessage PeopleInfo{string name1;// 姓名int32 age2;// 年龄message Phone{string number1;// 电话号码enumPhoneType{MP0;// 移动电话TEL1;// 固定电话}PhoneType type2;}repeated Phone phone3;// 电话google.protobuf.Any data4;// 地址// 社交联系方式 (多选一)oneof other_contact{string qq5;string wechat6;}mapstring,stringremark7;// 备注信息}// 通讯录修改消息名为ContactBook大驼峰避免和字段名contacts冲突message ContactBook{repeated PeopleInfo contacts1;}更新内容如下然后对这份 .proto 文件进行编译protoc--cpp_out. contacts.proto在 contacts.pb.h 更新的部分代码中对于 Map 类型的字段清空 mapclear_方法设置和获取获取方法的方法名称与小写字段名称完全相同。设置方法为mutable_方法返回值为 Map 类型的指针这类方法会为我们开辟好空间可以直接对这块空间的内容进行修改。2.2 更新 write.cc 文件代码如下#includeiostream#includefstream#includecontacts.pb.husingnamespacestd;usingnamespacecontacts;// 把命名空间展开// --- 强行补齐缺失的 Arena 模板实现 ---#includegoogle/protobuf/any.pb.hnamespacegoogle{namespaceprotobuf{templateAny*Arena::CreateMaybeMessageAny(Arena*arena){returnArena::CreateMessageInternalAny(arena);}}}// ----------------------------------// 新增联系人voidAddPeopleInfo(PeopleInfo*people){cout-------------新增联系人-------------endl;cout请输入联系人姓名: ;string name;getline(cin,name);people-set_name(name);cout请输入联系人年龄: ;intage;cinage;people-set_age(age);cin.ignore(256,\n);// 清除回车for(inti0;;i){cout请输入联系人电话i1 (输入回车即可完成电话新增): ;string number;getline(cin,number);if(number.empty()){break;}PeopleInfo_Phone*phonepeople-add_phone();phone-set_number(number);cout请输入该电话类型 (1、移动电话 2、固定电话): ;inttype;cintype;cin.ignore(256,\n);// 清除回车switch(type){case1:phone-set_type(PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP);// 设置移动电话break;case2:phone-set_type(PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);// 设置固定电话break;default:cout选择有误! endl;break;}}Address address;// 定义一个地址对象cout请输入联系人家庭地址: ;string homeAddress;getline(cin,homeAddress);address.set_home_address(homeAddress);cout请输入联系人单位地址: ;string unitAddress;getline(cin,unitAddress);address.set_unit_address(unitAddress);// 把Address类型的对象转化为Any类型people-mutable_data()-PackFrom(address);cout选择添加一个其他联系方式 (1、qq号 2、微信号): ;intotherContact;cinotherContact;cin.ignore(256,\n);if(1otherContact){cout请输入qq号: ;string qq;getline(cin,qq);people-set_qq(qq);}elseif(2otherContact){cout请输入微信号: ;string wechat;getline(cin,wechat);people-set_wechat(wechat);}else{cout非法选择, 该项设置失败! endl;}// 设置备注信息for(inti1;;i){cout请输入备注 i 标题 (只输入回车即可完成备注新增): ;string remark_key;getline(cin,remark_key);if(remark_key.empty())break;cout请输入备注 i 内容: ;string remark_value;getline(cin,remark_value);people-mutable_remark()-insert({remark_key,remark_value});}cout-----------添加联系人成功-----------endl;}intmain(){GOOGLE_PROTOBUF_VERIFY_VERSION;ContactBook contacts;// 读取本地已存在的通讯录文件fstreaminput(contacts.bin,ios::in|ios::binary);if(!input){coutcontacts.bin not find, create new file!endl;}elseif(!contacts.ParseFromIstream(input)){cerrparse error!endl;input.close();return-1;}// 向通讯录中添加一个联系人AddPeopleInfo(contacts.add_contacts());// 将通讯录写入本地文件中fstreamoutput(contacts.bin,ios::out|ios::trunc|ios::binary);if(!contacts.SerializeToOstream(output)){cerrwrite error!endl;input.close();output.close();return-1;}coutwrite success!endl;input.close();output.close();google::protobuf::ShutdownProtobufLibrary();return0;}更新内容如下2.3 更新 read.cc 文件代码如下#includeiostream#includefstream#includecontacts.pb.husingnamespacestd;usingnamespacecontacts;// 把命名空间展开// --- 强行补齐缺失的 Arena 模板实现 ---#includegoogle/protobuf/any.pb.hnamespacegoogle{namespaceprotobuf{templateAny*Arena::CreateMaybeMessageAny(Arena*arena){returnArena::CreateMessageInternalAny(arena);}}}// ----------------------------------// 打印联系人列表voidPrintContacts(ContactBookcontacts){for(inti0;icontacts.contacts_size();i){cout---------------联系人i1---------------endl;constPeopleInfopeoplecontacts.contacts(i);cout联系人姓名: people.name()endl;cout联系人年龄: people.age()endl;for(intj0;jpeople.phone_size();j){// 打印联系人电话constPeopleInfo_Phonephonepeople.phone(j);cout联系人电话j1: phone.number();// 这里不需要换行符// 打印联系人电话类型cout (phone.PhoneType_Name(phone.type()))endl;}// 如果data有数据 并且 data的数据类型是Address, 那么就打印联系人地址if(people.has_data()people.data().IsAddress()){Address address;people.data().UnpackTo(address);if(!address.home_address().empty()){cout联系人家庭地址: address.home_address()endl;}if(!address.unit_address().empty()){cout联系人单位地址: address.unit_address()endl;}}// 打印qq号或者微信号switch(people.other_contact_case()){casePeopleInfo::OtherContactCase::kQq:coutqq号: people.qq()endl;break;casePeopleInfo::OtherContactCase::kWechat:cout微信号: people.wechat()endl;break;default:break;}// 打印备注信息if(people.remark_size()){cout备注信息: endl;}for(autoitpeople.remark().cbegin();it!people.remark().cend();it){cout it-first: it-secondendl;}}}intmain(){GOOGLE_PROTOBUF_VERIFY_VERSION;ContactBook contacts;// 读取本地已存在的通讯录文件以二进制方式读取fstreaminput(contacts.bin,ios::in|ios::binary);if(!contacts.ParseFromIstream(input)){cerrparse error!endl;input.close();return-1;}// 打印通讯录列表PrintContacts(contacts);google::protobuf::ShutdownProtobufLibrary();return0;}更新内容如下2.4 编译运行使用 make 编译以后添加一个联系人。以上就 map 类型的全部内容。