【Protobuf速成指南】enum类型的使用

news/2024/10/31 1:30:47/

文章目录

  • 2.1枚举类型
    • 一、如何定义枚举类型?
    • 二、语法规范
    • 三、重定义问题
    • 四、enum类型相关函数
    • 五、Contact 2.1 改写
    • 六、总结

2.1枚举类型

 本系列文章将通过对通讯录项目的不断完善,带大家由浅入深的学习Protobuf的使用。这是Contacts的2.1版本,在这篇文章中将带大家学习Protobuf的enum类型语法,并将其用到我们的项目中

一、如何定义枚举类型?

.proto文件中可以定义枚举类型。如下我们可以定义了一个PhoneType枚举类型:

enum PhoneType{MOBILE = 0;FIXED = 1;
}

🎯[书写规范]:

  • 枚举类型名建议采用驼峰命名,开头大写
  • enum 类型成员被定义为具名常量。常量命名建议全部使用大写,多个字母之间使用_连接,例如:ENUM_COUNT = 0

二、语法规范

  • 0值常量必须存在,且要作为第一个元素。这是为了与proto2的语义兼容:第一个元素作为默认值,且值为0。

    // 错误示范1: 0值常量必须存在
    enum PhoneType{MOBILE = 1;FIXED = 2;
    }
    // 错误示范2:0值常量必须作为第一个元素
    enum PhoneType{FIXED = 1;MOBILE = 0;
    }
    
  • 枚举类型除了可以在消息外定义,也可以在消息体内定义(嵌套)

    message PeopleInfo{// ……enum PhoneType{FIXED = 0;MOBILE = 1;}
    }
    
  • 枚举的常量值在32位整数的范围内。但因负值无效因而不建议使用(与编码规则有关)

三、重定义问题

 将两个具有相同枚举值名称的枚举类型放在单个.proto文件下测试时,编译后会报错:某某某常量已经被定义。我们来总结这个问题

  1. 同级的枚举常量名不能重复

    //【错误】:同级的MOBILE名发生重复
    enum PhoneType{MOBILE = 0;
    }
    enum PhoneTypeCopy{MOBILE = 0;           
    }
    
  2. 处于非同级的枚举常量名可以重复

    // 【正确】: 处于不同级的枚举常量名可以重复
    enum PhoneType{MOBILE = 0;
    }message PeopleInfo{enum PhoneTypeCopy{MOBILE = 0;           }
    }
    
  3. 引入另一个.proto文件时,同级的枚举常量名不能重复

    // 【错误】:同级的MOBILE名发生重复
    // ----------------- phone.proto -------------------
    enum PhoneType{MOBILE = 0;
    }// ---------------- contact.prot -----------------
    import phone.proto
    enum PhoneType{MOBILE = 0;
    }
    
  4. 引入另一个.proto文件时,如果两个文件在不同的package下,则枚举常量名可以重复。package起到了隔离的作用,避免了冲突的发生

    // 【正确】:因为处于不同的package下
    // ----------------- phone.proto -------------------
    package phone
    enum PhoneType{MOBILE = 0;
    }// ---------------- contact.prot -----------------
    import phone.proto
    enum PhoneType{MOBILE = 0;
    }
    

🎯[总结]:

  • 同级的枚举常量名不能重复
  • 处于不同package下的常量名可以重复

四、enum类型相关函数

// 原始版本
message PeopleInfo{string name = 1;int32 age = 2;message Phone{  string number = 1;string type = 2;}repeated Phone phone = 3;
}

将Phone的type类型改为枚举类型:

// 修改后的版本
message PeopleInfo{string name = 1;int32 age = 2;message Phone{   string number = 1;enum PhoneType{MOBILE = 0;FIXED = 1;}PhoneType type = 2;}repeated Phone phone = 3;
}

对上面修改后的 .proto 文件进行编译后,观察生成的 .h 的变化

// 新生成了枚举类
enum PeopleInfo_Phone_PhoneType : int {PeopleInfo_Phone_PhoneType_MOBILE = 0,PeopleInfo_Phone_PhoneType_FIXED = 1,// ……
};

 对枚举类型 typePhoneType 类型新生成的部分函数(注意枚举常量名和枚举常量值表达意思的不同)

// 检验value是不是有效的枚举常量值
static inline bool PhoneType_IsValid(int value); // 返回枚举常量值对应的枚举常量名
static inline const std::string& PhoneType_Name(T enum_t_value)// 将枚举常量名解析为对应的枚举常量值
static inline bool PhoneType_Parse(const std::string& name, 			PhoneType* value) // -----------------------------------------------------------------// 获取type的枚举常量值
::contacts::PeopleInfo_Phone_PhoneType type() const;// 设置为默认值,即值为0的枚举值
void clear_type();// 设置枚举类型值
void set_type(::contacts::PeopleInfo_Phone_PhoneType value);
// value 为上一代码块提到的枚举类,例如“PeopleInfo_Phone_PhoneType_MOBILE”

五、Contact 2.1 改写

write.cc修改

#include <iostream>
#include <fstream>
#include "contact.pb.h"using namespace std;void AddPeopleInfo(contact2::PeopleInfo* p){cout << "----------新增联系人----------" << endl;cout << "请输入联系人姓名: ";string name;getline(cin, name);p->set_name(name);cout << "请输入联系人年龄: ";int age;cin >> age;p->set_age(age);// 一直清空,直到读到 \n(\n也会被清除),或者清空,直到清空了256个字符cin.ignore(256, '\n'); // 说明:cin输入后,换行符还会被留在缓冲区中,而getline读到\n就停了// 所以需要使用 cin.ignore 清空缓冲区从而避免对之后的输入产生影响for(int i = 0;; i++){cout << "请输入联系人电话"  << i + 1 << "(只输入回车则结束): ";string number;getline(cin, number);if(number.empty()) break;contact2::PeopleInfo_Phone* phone = p->add_phone();phone->set_number(number);// ------------------修改部分-----------------------cout << "请选择电话类型: (0:MOBIle   1:FIXED)";int type;cin >> type;cin.ignore(256, '\n');switch(type){case 0:phone->set_type(contact2::PeopleInfo_Phone_PhoneType_MOBILE);break;case 1:phone->set_type(contact2::PeopleInfo_Phone_PhoneType_FIXED);break;default:cout << "非法选择, 将采用默认值" << endl;}// ---------------------修改部分---------------------}cout << "-----------添加成功-----------" << endl;
}int main(int argc, char* argv[]){if(argc != 2){cerr << "use: ./write filename" << endl;exit(1);}contact2::Contact contact;// 1. 读取通讯录中的原始数据fstream input(argv[1], ios::in | ios::binary);  // 二进制的方式读取if(!input){cerr << argv[1] << " file not find. Creating a new file" << endl;} else if(!contact.ParseFromIstream(&input)){    // 从输出流中反序列化cerr << "parser original file error" << endl;exit(2); }// 2. 新增联系人AddPeopleInfo(contact.add_contact());// 3. 写入文件中fstream output(argv[1], ios::out | ios::trunc | ios::binary);if(!output || !contact.SerializePartialToOstream(&output)){cerr << "write error" << endl;exit(3);}cout << "write success" << endl;input.close();output.close();
}

image-20230608102039649

read.cc修改

#include <iostream>
#include <fstream>
#include "contact.pb.h"using namespace std;void PrintContact(contact2::Contact& contact){for(int i = 0; i < contact.contact_size(); i++){ const contact2::PeopleInfo people = contact.contact(i);cout << "-------------联系人" << i + 1 << "-------------" << endl;cout << "name: " << people.name() << endl;cout << "age: " << people.age() << endl;;int j = 1;// ---------------------修改部分---------------------------// phone.type()枚举常量值// PhoneType_Name根据枚举常量值来返回对应的枚举常量名for(const auto& phone : people.phone()){cout << "number" << j++ << ": " << phone.number()<< " type: " << phone.PhoneType_Name(phone.type()) << endl;// ---------------------修改部分---------------------------}}
}int main(int argc, char* argv[])
{if(argc != 2){cerr << "use: ./read file" << endl;exit(1);}contact2::Contact contact;// 1. 读取通讯录中的原始数据fstream input(argv[1], ios::in | ios::binary);  // 二进制的方式读取if(!input){cerr << argv[1] << " file not find. exit" << endl;exit(2);} else if(!contact.ParseFromIstream(&input)){    // 从输出流中反序列化cerr << "parser original file error" << endl;exit(2); }PrintContact(contact);input.close();return 0;
}

image-20230608102102029

🎯[说明]:

​  "张三"是我们上次插入的数据,我们并没有对其type类型进行赋值,但是根据proto的语法,对于没有赋值的枚举类型,默认设置枚举常量值为0

六、总结

在这里插入图片描述


http://www.ppmy.cn/news/276484.html

相关文章

3.多线程之JUC并发编程0

1.学习方法 java1.8才有juc 面试高频问 源码官方文档 2.什么是juc 三个包 java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks 介绍 Callable性能比Runnable高,并且Runnable没有返回值进程和线程 进程: 一个程序比如QQ.exe 线程 在QQ里面同时打字和…

【Hello MySQL】数据库基础

目录 1. 什么是数据库 2. 主流数据库 3. MySQL的基本使用 3.1 MySQL安装 3.2 连接 MySQL 服务器 3.3 退出 MySQL 服务器 3.4 服务器&#xff0c;数据库&#xff0c;表关系 3.5 MySQL的配置 4. MySQL架构 5. SQL分类 6. 存储引擎 6.1 存储引擎 6.2 查看存储引擎 6.3 存储引擎对…

下载m3u8

M3U8 是 Unicode 版本的 M3U&#xff0c;用 UTF-8 编码。“M3U” 和 “M3U8” 文件都是苹果公司使用的 HTTP Live Streaming&#xff08;HLS&#xff09; 协议格式的基础。 HLS 的工作原理是把整个流分成一个个小的基于 HTTP 的文件来下载&#xff0c;每次只下载一些。当媒体流…

wifi无线破解(BT4)

使用BT4破解无线网&#xff1a;&#xff08;三条命令版&#xff09; 1、下载镜像文件。 到 www.backtrack-linux.org下载BT4 &#xff0c;我下的是 BT4-R1版的&#xff0c;目前来说是最新的。最好不要直接从直接点那个下载链接&#xff0c;感觉有点慢&#xff0c;先下那个种子就…

TBC4.1下载

下载地址&#xff1a;https://www.trimble.com/globalTRL.asp?navCollection-36339 Downloads New Release - TBC 4.10 (64-bit only) Trimble Business Center 4.10 Patch 1 (64-bit) Full InstallTBC 4.10 Release Notes (English) (1841 KB)(1769 KB) (46936 KB)Trimble…

bt4的U盘安装方法

本来想在U盘里装个bt3玩玩&#xff0c;但发现在我的机子上进不去系统&#xff0c;就连字符模式都不行&#xff0c;具体原因还不清楚。后来发现在另外一个室友的机子上倒是可以&#xff0c;但也不能拿人家的机子上干这种事吧!所以还是狠狠心&#xff0c;买了个大点的U盘&#xf…

一个简单易用的m3u8下载器,支持下载m3u8链接或文件为mp4或ts格式

███╗ ██╗ ███╗ ███╗██████╗ ██╗ ██╗ █████╗ ██████╗ ██╗ ██████╗██╗ ██╗ ████╗ ██║ ████╗ ████║╚════██╗██║ ██║██╔══██╗██╔══██…

BackTrack 3 Final BT3下载地址

BackTrack 3 Final 光盘版 Name:: bt3-final.iso Size: 695 MB Download: http://ftp.cc.uoc.gr/mirrors/linux/backtrack/bt3-final.iso MD5: f79cbfbcd25147df32f5f6dfa287c2d9 SHA1: 471f0e41931366517ea8bffe910fb09a815e42c7 BackTrack 3 Final USB版 Name:: bt3final_us…