• 《protobuf》基础语法2


    枚举类型

    protobuf里有枚举类型,定义如下

    enum PhoneType
    {
    	string home_addr = 0;
    	string work_addr = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    message一样,可分为 嵌套定义,文件内定义,文件外定义。不过多演示

    但是值得注意的点是

    1. 同级(同层)的枚举类型,各个枚举类型中的常量不能重名,否则编译会报错。如下:
    enum A
    {
    	int32 a = 0;
    }
    enum B
    {
    	int32 a = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    A和B有相同的变量a,所以会报错

    1. 单个 .proto 文件下,最外层枚举类型和嵌套枚举类型,不算同级。如下:
    enum A
    {
    	int32 a = 0;
    }
    message C
    {
    	enum B
    	{
    		int32 a = 0;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 多个 .proto 文件下,若一个文件引入了其他⽂件,且每个文件都未声明 package,每个 proto 文
      件中的枚举类型都在最外层,算同级。如下:
    // 在 A.proto 文件里
    import "B.proto"
    enum A
    {
    	int32 a = 0;   // 报错,B.proto 里以及定义
    }
    -----------------------
    // 在 B.proto 文件里
    enum B
    {
    	int32 a = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 多个 .proto 文件下,若一个文件引入了其他文件,且每个文件都声明了 package,不算同级。如下
    // 在 A.proto 文件里
    import "B.proto"
    package A;
    enum A
    {
    	int32 a = 0;
    }
    -----------------------
    // 在 B.proto 文件里
    package B;
    enum B
    {
    	int32 a = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ANY 类型

    介绍一下ANY类型,ANY类型表示任意类型

    • 头文件位置 /usr/local/protobuf/include/google/protobuf/
      在这里插入图片描述

    如何将其引入 .proto 文件里

    // 在/usr/local/protobuf/include
    import "google/protobuf/any.proto";
    // 使用
    message Any{
    	google.protobuf.Any data = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 介绍常用函数:
    // 已知信息如下
    / contacts.proto文件  //
    syntax = "proto3"
    package contacts;
    import "google/protobuf/any.proto";  // 引入Any类型
    message PeopleInfo
    {
    	// 可以用于任何类型的any
    	google.protobuf.Any data = 1;
    }
    
    message Address
    {
    	string home_addr;
    }
    
     test.cc文件 //
    #include 
    #include "contacts.pb.h"  // contacts.proto 编译后生成的头文件
    using namespace std;
    
    int main()
    {
        // 包装
    	contact2::PeopleInfo people;
    	contact2::Address addr;
    	addr.set_home_addr("中国");
    	google::protobuf::Any* any = people.mutable_data();  // 开辟一段any对象的空间
        any->PackFrom(addr);  // 将addr打包成Any类型
    
        // 转换
        contact2::Address addr2;
        if(people.has_data())
        {
            google::protobuf::Any any = people.data();  // 获取people里的Any类对象 
            if(any.Is<contact2::Address>()) // 判断any类型是否为 Address 类
            {
                any.UnpackTo(&addr2);  // 输出型参数,填充add2
                cout << addr2.home_addr() << endl;  // 打印
            }
        }
        
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    编译 .proto 文件,然后编译连接 test.cc 文件,执行结果如下:
    在这里插入图片描述

    执行大致流程
    在这里插入图片描述
    分类讲解一下常用函数:

    • 属于people对象的
      • Any* mutable_data(); ------- // 开辟一段 any 对象的空间
      • Any& data() const; ----------- // 获得 any 对象(即:people里的data)
      • bool has_data() const; ------- // 判断有无对 any 对象赋值
    • 属于 people 里 Any类型的data 对象的
      • bool PackFrom(const Message& message); -------- // 将任意类型转换成 Any 类
      • bool UnpackTo(Message* message) const; -------- // 将 any 对象里的值赋给相对应类型的对象
      • template< class T> bool Is() const; -------- // 判断是否为对应类型

    oneof 类型

    oneof 类型语法简单:

    • 定义如下
    message PeopleInfo
    {
    	string name = 1;
    	oneof gender
    	{
    		string male = 2;
    		string female = 3;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    但是值得注意的点是

    • 可选字段中的字段编号,不能与非可选字段的编号冲突。
    • 不能在 oneof 中使用 repeated 字段。
    • 将来在设置 oneof 字段中值时,如果将 oneof 中的字段设置多个,那么只会保留最后⼀次设置的成员,之前设置的 oneof 成员会自动清除。

    看看编译后的 .pb.h 文件里定义的内容

    class PeopleInfo final :
        public ::PROTOBUF_NAMESPACE_ID::Message 
    {
    	enum GenderCase 
    	{
    	 kMale = 2,
    	 kFemale = 3,
    	 GENDER_NOT_SET = 0,
    	};
    
      // string male = 2;
      bool has_male() const;
      void clear_male();
      const std::string& male() const;
      template <typename ArgT0 = const std::string&, typename... ArgT>
      void set_male(ArgT0&& arg0, ArgT... args);
      std::string* mutable_male();
      PROTOBUF_NODISCARD std::string* release_male();
      void set_allocated_male(std::string* male);
    
      // string female = 3;
      bool has_female() const;
      void clear_female();
      const std::string& female() const;
      template <typename ArgT0 = const std::string&, typename... ArgT>
      void set_female(ArgT0&& arg0, ArgT... args);
      std::string* mutable_female();
      PROTOBUF_NODISCARD std::string* release_female();
      void set_allocated_female(std::string* female);
    
      void clear_gender();
      GenderCase gender_case() const;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    会将 oneof 中的多个字段定义为⼀个枚举类型。

    • 设置和获取:对 oneof 内的字段进⾏常规的设置和获取即可,但要注意只能设置⼀个。如果设置多个,那么只会保留最后⼀次设置的成员
    • 清空oneof字段:clear_ 方法
    • 获取当前设置了哪个字段:_case 方法
    • 设置值方法: set_
    • 判断该值是否存在方法:has_

    map 类型

    类似于C++里面的 map 类型,protobuf自己实现了一个类似的数据结构,protobuf 的 map 类型的实现是基于它的 Message 类型的。

    • 定义如下
    message PeopleInfo
    {
    	map<string, string> info = 1;
    }
    
    • 1
    • 2
    • 3
    • 4

    但是值得注意的点是

    repeated map< key_type, value_type> map_name = N;

    • key_type 是除了 float 和 byte 的其他任何标量类型。value_type 可以是任意类型
    • map 也不可以被 repeated 修饰
    • map 中存入的元素是无序

    讲解一下几个相关常用函数

    • 在PeopleInfo对象里,一般用 mutable_info ( 这里的 info 是对应map类对象 info ) 来开辟一段空间,返回 map 指针来操控info。
      函数原型Map< std::string, std::string >*mutable_info()
    • void clear_info(); 清空对象里的内容。

    此外,map还支持迭代器,和C++里的 unorderedmap 十分类似。

    改进通讯录实例

    运用上述知识点,对上一篇的通讯录代码进行增添功能

    contacts.proto

    syntax = "proto3";
    package contact2;
    
    // 在/usr/local/protobuf/include
    import "google/protobuf/any.proto";
    
    // 地址信息
    message Address
    {
        string home_addr = 1;
        string work_addr = 2;
    }
    // 个人信息
    message PeopleInfo
    {
        string name = 1;
        int32 age = 2;
        // 嵌套定义
        message Phone{
            string number = 1;
            // 嵌套枚举
            enum PhoneType{
                MP = 0;  // 移动电话
                TEL = 1; // 固定电话
            }
            PhoneType type = 2;
        }
        // repeated 修饰词 修饰的变量相当于数组
        repeated Phone phone = 3;
        google.protobuf.Any data = 4;
        // 其他联系方式
        oneof other_contacts
        {
            string QQ = 5;
            string Wechat = 6;
        }
        // 备注
        map<string, string> remark = 7;
    }
    
    // 通讯录
    message Contacts
    {
        repeated PeopleInfo contacts = 1;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    write.cpp
    在这里插入图片描述

    执行结果

    在这里插入图片描述

    read.cpp

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    系统编程 day10 管道的知识 (无名管道 ,有名管道 ,管道通信,管道的函数,管道的知识(什么是管道 ,,,) )
    手工计算深度学习模型是如何更新参数的
    【Docker】查看每层镜像的大小
    内容+货架“攻防一体”,京东能否上演“后来居上”?
    C++人生重开模拟器
    Django学习第一天
    ArcGIS小技巧|四种计算图斑面积的方法
    Filebeat和logstash 使用过程中遇到的一些小问题记录
    Spring事务
    CAS登录认证
  • 原文地址:https://blog.csdn.net/qq_56166591/article/details/132782081