当前位置: 首页 > 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.jsqmd.com/news/535505/

相关文章:

  • 别再只盯着Mesh了!聊聊NoC拓扑选型:从Ring、Torus到Fat Tree,你的芯片设计该怎么选?
  • 2026年郭氏正骨怎么选?三招教你辨真伪选好店,做得好的郭氏正骨聚焦优质品牌综合实力分析 - 品牌推荐师
  • 5大场景解放80%重复工作:n8n-nodes-puppeteer自动化浏览器操作全指南
  • VSCode远程开发新姿势:用Remote-SSH直连Docker容器(附端口避坑指南)
  • 8-Bit硬边框UI×AI生成:Pixel Fashion Atelier界面交互设计与技术实现揭秘
  • OpenClaw+nanobot:QQ聊天机器人配置全流程解析
  • 开源项目问题解决:Ruffle Flash模拟器扩展故障全维度技术方案
  • 为什么90%的Dify RAG项目在生产环境召回率跌破65%?——来自金融/医疗双行业高合规场景的5条血泪法则
  • 《90%考生不知道的蓝桥杯Web提分秘籍!这本书让我一个月逆袭省一》
  • 用快马实践vibe coding:5分钟AI生成你的个人博客原型
  • CVPR2024底层视觉新趋势:用Diffusion模型搞定超分、去噪、修复,实战配置教程(含代码)
  • nli-distilroberta-base模型效果深度评测:多领域文本蕴含任务实战
  • UnityFPSUnlocker深度指南:解锁安卓Unity游戏帧率的终极方案
  • 零拷贝到底是个什么东西?
  • 零基础入门:ComfyUI工作流详解,手把手教你修复泛黄老照片
  • Bypass Paywalls Clean完全使用指南:突破网络内容访问限制的开源方案
  • 开发者效率提升:OpenClaw+Qwen3-32B自动化测试流水线
  • SDMatte与YOLOv11协同工作流:先检测后抠图的自动化流程
  • YALMIP实战:如何用5行代码搞定线性规划问题(含Mosek求解器配置技巧)
  • 如何快速掌握实时语音变换:从新手到专家的完整指南
  • 滤波实战:从原理到代码的平滑之旅
  • 运维工作梳理
  • 2026降AI率工具红黑榜:哪些降AI软件真正靠谱?实测推荐 - 我要发一区
  • Stata数据处理实战:5分钟搞定Wind/EPS面板数据转换(附报错解决方案)
  • 【VMD实战】从包络谱到熵特征:Python实现信号分解与故障诊断全流程解析
  • 基于扣子智能体的智能客服系统:从架构设计到生产环境部署实战
  • Windows下Nuitka打包踩坑实录:自动下载GCC慢?那是你没配好MSVC环境
  • IDM轻松抓取动态资源技巧
  • 3.25软工
  • 岛屿的数量-leetcode