当前位置: 首页 > news >正文

【ProtoBuf 语法详解】map 类型

文章目录

  • 1. map 类型
  • 2. 升级通讯录至 2.4 版本
    • 2.1 更新 contacts.proto 文件
    • 2.2 更新 write.cc 文件
    • 2.3 更新 read.cc 文件
    • 2.4 编译运行

1. map 类型

该语法支持创建一个关联映射字段,也就是可以使用 map 类型去声明字段类型,格式为:

map<key_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 文件

代码如下:

syntax="proto3";package contacts;// package 是一个可选的声明符, 声明其命名空间// 引入 any.proto 文件import"google/protobuf/any.proto";// 地址message Address{string home_address=1;// 家庭地址string unit_address=2;// 单位地址}// 定义联系人messagemessage PeopleInfo{string name=1;// 姓名int32 age=2;// 年龄message Phone{string number=1;// 电话号码enumPhoneType{MP=0;// 移动电话TEL=1;// 固定电话}PhoneType type=2;}repeated Phone phone=3;// 电话google.protobuf.Any data=4;// 地址// 社交联系方式 (多选一)oneof other_contact{string qq=5;string wechat=6;}map<string,string>remark=7;// 备注信息}// 通讯录:修改消息名为ContactBook(大驼峰,避免和字段名contacts冲突)message ContactBook{repeated PeopleInfo contacts=1;}

更新内容如下:

然后对这份 .proto 文件进行编译:

protoc--cpp_out=. contacts.proto

在 contacts.pb.h 更新的部分代码中,对于 Map 类型的字段:

  • 清空 map:clear_方法
  • 设置和获取:获取方法的方法名称与小写字段名称完全相同。
  • 设置方法为mutable_方法,返回值为 Map 类型的指针,这类方法会为我们开辟好空间,可以直接对这块空间的内容进行修改。

2.2 更新 write.cc 文件

代码如下:

#include<iostream>#include<fstream>#include"contacts.pb.h"usingnamespacestd;usingnamespacecontacts;// 把命名空间展开// --- 强行补齐缺失的 Arena 模板实现 ---#include<google/protobuf/any.pb.h>namespacegoogle{namespaceprotobuf{template<>Any*Arena::CreateMaybeMessage<Any>(Arena*arena){returnArena::CreateMessageInternal<Any>(arena);}}}// ----------------------------------// 新增联系人voidAddPeopleInfo(PeopleInfo*people){cout<<"-------------新增联系人-------------"<<endl;cout<<"请输入联系人姓名: ";string name;getline(cin,name);people->set_name(name);cout<<"请输入联系人年龄: ";intage;cin>>age;people->set_age(age);cin.ignore(256,'\n');// 清除回车for(inti=0;;i++){cout<<"请输入联系人电话"<<i+1<<" (输入回车即可完成电话新增): ";string number;getline(cin,number);if(number.empty()){break;}PeopleInfo_Phone*phone=people->add_phone();phone->set_number(number);cout<<"请输入该电话类型 (1、移动电话 2、固定电话): ";inttype;cin>>type;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;cin>>otherContact;cin.ignore(256,'\n');if(1==otherContact){cout<<"请输入qq号: ";string qq;getline(cin,qq);people->set_qq(qq);}elseif(2==otherContact){cout<<"请输入微信号: ";string wechat;getline(cin,wechat);people->set_wechat(wechat);}else{cout<<"非法选择, 该项设置失败! "<<endl;}// 设置备注信息for(inti=1;;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){cout<<"contacts.bin not find, create new file!"<<endl;}elseif(!contacts.ParseFromIstream(&input)){cerr<<"parse error!"<<endl;input.close();return-1;}// 向通讯录中添加一个联系人AddPeopleInfo(contacts.add_contacts());// 将通讯录写入本地文件中fstreamoutput("contacts.bin",ios::out|ios::trunc|ios::binary);if(!contacts.SerializeToOstream(&output)){cerr<<"write error!"<<endl;input.close();output.close();return-1;}cout<<"write success!"<<endl;input.close();output.close();google::protobuf::ShutdownProtobufLibrary();return0;}

更新内容如下:

2.3 更新 read.cc 文件

代码如下:

#include<iostream>#include<fstream>#include"contacts.pb.h"usingnamespacestd;usingnamespacecontacts;// 把命名空间展开// --- 强行补齐缺失的 Arena 模板实现 ---#include<google/protobuf/any.pb.h>namespacegoogle{namespaceprotobuf{template<>Any*Arena::CreateMaybeMessage<Any>(Arena*arena){returnArena::CreateMessageInternal<Any>(arena);}}}// ----------------------------------// 打印联系人列表voidPrintContacts(ContactBook&contacts){for(inti=0;i<contacts.contacts_size();i++){cout<<"---------------联系人"<<i+1<<"---------------"<<endl;constPeopleInfo&people=contacts.contacts(i);cout<<"联系人姓名: "<<people.name()<<endl;cout<<"联系人年龄: "<<people.age()<<endl;for(intj=0;j<people.phone_size();j++){// 打印联系人电话constPeopleInfo_Phone&phone=people.phone(j);cout<<"联系人电话"<<j+1<<": "<<phone.number();// 这里不需要换行符// 打印联系人电话类型cout<<" ("<<phone.PhoneType_Name(phone.type())<<")"<<endl;}// 如果data有数据 并且 data的数据类型是Address, 那么就打印联系人地址if(people.has_data()&&people.data().Is<Address>()){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:cout<<"qq号: "<<people.qq()<<endl;break;casePeopleInfo::OtherContactCase::kWechat:cout<<"微信号: "<<people.wechat()<<endl;break;default:break;}// 打印备注信息if(people.remark_size()){cout<<"备注信息: "<<endl;}for(autoit=people.remark().cbegin();it!=people.remark().cend();++it){cout<<" "<<it->first<<": "<<it->second<<endl;}}}intmain(){GOOGLE_PROTOBUF_VERIFY_VERSION;ContactBook contacts;// 读取本地已存在的通讯录文件(以二进制方式读取)fstreaminput("contacts.bin",ios::in|ios::binary);if(!contacts.ParseFromIstream(&input)){cerr<<"parse error!"<<endl;input.close();return-1;}// 打印通讯录列表PrintContacts(contacts);google::protobuf::ShutdownProtobufLibrary();return0;}

更新内容如下:

2.4 编译运行

使用 make 编译以后,添加一个联系人。

以上就 map 类型的全部内容。

http://www.cnnetsun.cn/news/1479303.html

相关文章:

  • 库卡机器人零位校准全流程实操指南:从首次调试到碰撞后修正
  • 硬件可调PWM
  • Cortex-M软件串口库SoftwareSerialM原理与实战
  • ChatGPT发展中的效率提升:从模型优化到工程实践
  • Prompt—— 被 “高端术语” 包装的基础操作
  • 如何轻松构建个人ASMR音频库:asmr-downloader使用指南
  • 为什么90%的Dify RAG项目在生产环境召回率跌破65%?——来自金融/医疗双行业高合规场景的5条血泪法则
  • Python数据可视化:从入门到精通的Colormaps实战
  • AI 辅助开发实战:自动化专业毕业设计选题的智能生成与验证系统
  • SEO_从关键词到外链,详解SEO优化的完整工作流程
  • 【仅开放72小时】MCP本地数据库连接器性能压测报告(QPS提升417%,P99延迟<12ms)及可复用的benchmark工具包
  • 三步打造赛马娘DMM版专属优化方案:从问题诊断到效果验证
  • Qwen3.5-4B-Claude-Opus镜像免配置实战:CSDN平台开箱即用Web问答部署
  • AI角色一键生成工具正在改写3D创作流程:V2Fun.art+香蕉2,更丝滑的创作体验
  • 突破限制:开源Unlocker工具实现VMware跨平台macOS兼容全攻略
  • 嵌入式网络通信中IP地址动态配置方案与实践
  • 干货合集:10个降AI率网站测评,专科生必看!
  • 3步轻松搞定QQ音乐加密格式:QMCDecode完全指南
  • 3步打造个性化终端:Ghostty配置进阶指南
  • Qwen-Image-Edit模型架构解析:技术深度剖析
  • GPS卫星位置解算实战:从C语言代码到测绘应用(附完整源码解析)
  • PLUTO SDR进阶指南:通过固件修改解锁AD9363的6GHz潜力
  • 终极指南:如何用实时语音变换工具重塑你的声音体验 [特殊字符]
  • 基于Laravel的企业级IT资产管理系统架构:构建可观测性驱动的资产全生命周期治理平台
  • UiTrainplanRequest 前后台前端调用公用实现,代码上有什么建议
  • Vue 3防作弊组件实战:5分钟搞定在线考试系统的切屏检测与复制粘贴禁用
  • Vue Toast组件:轻量级通知解决方案的无侵入式集成实践
  • Parabolic视频下载神器:200+网站支持的终极跨平台下载解决方案
  • 惊艳效果展示:实时手机检测-通用镜像识别复杂场景手机案例
  • 康威生命游戏中的简易CPU设计与实现