尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【ProtoBuf 语法详解】oneof 类型

【ProtoBuf 语法详解】oneof 类型 文章目录1. oneof 类型2. 升级通讯录至 2.3 版本2.1 更新 contacts.proto 文件2.2 更新 write.cc 文件2.3 更新 read.cc 文件2.4 编译运行1. oneof 类型如果消息中有很多可选字段并且将来同时只有一个字段会被设置那么就可以使用oneof加强这个行为也能有节约内存的效果。2. 升级通讯录至 2.3 版本通讯录 2.3 版本想新增联系人的其他联系方式比如 qq 或者 wechat 二选一我们就可以使用 oneof 字段来加强多选一这个行为。oneof 字段定义的格式为oneof 字段名 { 字段1; 字段2; ... }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; // 单位地址 } // 定义联系人message message PeopleInfo { string name 1; // 姓名 int32 age 2; // 年龄 message Phone { string number 1; // 电话号码 enum PhoneType { 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; } } // 通讯录修改消息名为ContactBook大驼峰避免和字段名contacts冲突 message ContactBook { repeated PeopleInfo contacts 1; }更新内容如下注意可选字段中的字段编号不能与非可选字段的编号冲突。不能在 oneof 中使用 repeated 字段。将来在设置 oneof 字段中值时如果将 oneof 中的字段设置多个那么只会保留最后一次设置的成员之前设置的 oneof 成员会自动清除。然后更新代码protoc--cpp_out. contacts.proto在 contacts.pb.h 更新的代码中对于 oneof 字段会将 oneof 中的多个字段定义为一个枚举类型。设置和获取对 oneof 内的字段进行常规的设置和获取即可但要注意只能设置一个。如果设置多个那么只会保留最后一次设置的成员。清空 oneof 字段clear_方法获取当前设置了哪个字段_case方法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;}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;}}}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 编译以后新增一个联系人。以上就是 oneof 语法的详细用法。
返回列表