《protobuf》基础语法2

文章目录

  • 枚举类型
  • ANY 类型
  • oneof 类型
  • map 类型
  • 改进通讯录实例

枚举类型

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

enum PhoneType
{
	string home_addr = 0;
	string work_addr = 1;
}

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

但是值得注意的点是

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

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

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

ANY 类型

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

  • 头文件位置 /usr/local/protobuf/include/google/protobuf/
    《protobuf》基础语法2_第1张图片

如何将其引入 .proto 文件里

// 在/usr/local/protobuf/include
import "google/protobuf/any.proto";
// 使用
message Any{
	google.protobuf.Any data = 1;
}
  • 介绍常用函数:
// 已知信息如下
/ 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;
}

编译 .proto 文件,然后编译连接 test.cc 文件,执行结果如下:
《protobuf》基础语法2_第2张图片

执行大致流程
《protobuf》基础语法2_第3张图片
分类讲解一下常用函数:

  • 属于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;
	}
}

但是值得注意的点是

  • 可选字段中的字段编号,不能与非可选字段的编号冲突。
  • 不能在 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;
}

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

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

map 类型

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

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

但是值得注意的点是

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;
}

write.cpp
《protobuf》基础语法2_第4张图片

执行结果

《protobuf》基础语法2_第5张图片

read.cpp

《protobuf》基础语法2_第6张图片
《protobuf》基础语法2_第7张图片

你可能感兴趣的:(#,protobuf,中间件)