protobuf 中复合数据类型的读写

7 篇文章 1 订阅

背景

protobuf 在生成的 C++ 代码中为 .proto 文件中的每个 message 生成了对应的 C++ 类,并提供了数据成员的读写方法。

message 类型读写

①.message 示例

message Point
{
   double lng = 1;
   double lat = 2;
}
message DemoMsg
{
   int32 id = 1;
   Point pos = 2;
}

②.成员赋值

通过 mutable_xxx 方法返回的指针给成员赋值:

 protoTest::DemoMsg msg; 
 msg.set_id(100);
 
 msg.mutable_pos()->set_lng(112.56);
 msg.mutable_pos()->set_lat(56.78);
 cout << msg.DebugString() << endl;

在这里插入图片描述

通过 copyFrom 方法使用结构体赋值:

protoTest::DemoMsg msg; 
msg.set_id(100);

protoTest::Point m_p;
m_p.set_lng(112.56);
m_p.set_lat(56.78);

msg.mutable_pos()->CopyFrom(m_p);
cout << msg.DebugString() << endl;

通过 set_allocated_xxx 成员函数传入指针进行赋值:

protoTest::DemoMsg msg; 
msg.set_id(100);

protoTest::Point * m_p = new  protoTest::Point;
m_p->set_lng(112.56);
m_p->set_lat(56.78);

msg.set_allocated_pos(m_p);
cout << msg.DebugString() << endl;

③.成员读取

通过成员函数 has_xxx 可以判断 message 类型的成员是否被赋值。

protoTest::Point* m_p = new  protoTest::Point;
m_p->set_lng(112.56);
m_p->set_lat(56.78);

protoTest::DemoMsg msg; 
msg.set_id(100);
msg.set_allocated_pos(m_p);

if (msg.has_pos())
{
    auto& pos = msg.pos();
    cout << pos.lng() << " " << pos.lat();
}

在这里插入图片描述

map 类型读写

①.message 示例

message DemoMsg
{
   map<int32,string>  a = 1;    
}

②.成员赋值

map 类型成员赋值需通过 mutable_xxx 方法进行:

protoTest::DemoMsg msg; 
msg.mutable_a()->insert({ 1,"aaaaa" });
msg.mutable_a()->insert({ 2,"bbbbb" });
msg.mutable_a()->insert({ 3,"ccccc" });   
cout << msg.DebugString() << endl;

在这里插入图片描述

③.成员读取

protoTest::DemoMsg msg; 
msg.mutable_a()->insert({ 1,"aaaaa" });
msg.mutable_a()->insert({ 2,"bbbbb" });   
auto map = msg.mutable_a();
if (map->contains(1))
{
    cout << map->at(1) << endl;
}

在这里插入图片描述

any 类型读写

①.概述

any 可以保存任意的已知类型的序列化数据,常用于对结构体数据的再包装,即可以把不同类型的 message 包装在同一个 message 中进行传输。

②.message 示例

syntax = "proto3";
import "google/protobuf/any.proto";
package protoTest;

message Point
{
   double lng = 1;
   double lat = 2;
}
message Node
{
   int32 id = 1;
   string name = 2;
}
message DemoMsg
{
   int32 id = 1;
   google.protobuf.Any data = 2;
}

③.成员赋值

使用 any 类型的成员函数 PackFrom 来进行赋值。

protoTest::Point m_p;
m_p.set_lng(112.56);
m_p.set_lat(56.78);

protoTest::DemoMsg msg; 
msg.set_id(1);
msg.mutable_data()->PackFrom(m_p);
    
cout << msg.DebugString() << endl;

在这里插入图片描述

④.message 类型判断

通过成员函数 Is 可以判断是否为指定类型的数据。

protoTest::Point m_p;
m_p.set_lng(112.56);
m_p.set_lat(56.78);

protoTest::Node m_node;
m_node.set_id(1);
m_node.set_name("Zhangsan");

protoTest::DemoMsg msg1; 
msg1.set_id(1);
msg1.mutable_data()->PackFrom(m_p);

protoTest::DemoMsg msg2;
msg2.set_id(2);
msg2.mutable_data()->PackFrom(m_node);

auto checkAny = [&](const protoTest::DemoMsg& msg) {
    if (msg.data().Is<protoTest::Point>())
         cout << " msgID:" << msg.id() << " 中 data 类型为 Point " << endl;
    else if( msg.data().Is<protoTest::Node>() )
         cout << " msgID:" << msg.id() << " 中 data 类型为 Node " << endl;
};
    
checkAny(msg1);
checkAny(msg2);

在这里插入图片描述

⑤.成员读取

通过成员函数 UnpackTo 可以把 any 数据还原成对应的结构体数据。

protoTest::Point m_p;
m_p.set_lng(112.56);
m_p.set_lat(56.78);

protoTest::DemoMsg msg; 
msg.set_id(1);
msg.mutable_data()->PackFrom(m_p);
  
if (msg.data().Is<protoTest::Point>())
{
    protoTest::Point pos;
    if (msg.data().UnpackTo(&pos))
    {
        cout << pos.DebugString() << endl;
    }
}

在这里插入图片描述

oneof 类型读写

①.概述

oneof 类型同 C++ 中的 union 类型,同一时刻只有一种类型有效。

②.message 示例

message DemoMsg
{
   oneof test{
     int32 id = 1;
  string name =2;
   };
}

③.成员赋值

直接使用 set_xxx 给相应的成员赋值即可,但只有最后一次赋值的数据有效。

protoTest::DemoMsg msg;  
msg.set_id(100);
msg.set_name("123");

cout << msg.DebugString() << endl;

④.数据类型判断

通过 has_xxx 方法判断对应类型成员是否赋值:

protoTest::DemoMsg msg;  
msg.set_id(100);
msg.set_name("123");

if (msg.has_name())
{
    cout << "msg 中为 string 类型" << endl;
}

在这里插入图片描述

通过 xxx_case 方法当前判断保存的成员类型:

protoTest::DemoMsg msg;  
msg.set_id(100);
msg.set_name("123");

switch (msg.test_case())
{
   case protoTest::DemoMsg::kId:
       cout << "msg 中为 int32 类型" << endl; break;
   case protoTest::DemoMsg::kName:
       cout << "msg 中为 string 类型" << endl; break;
   default:
       break;
}

⑤.成员读取

先判断当前保存的字段类型,再读取数据。

protoTest::DemoMsg msg;  
msg.set_id(100);
msg.set_name("123");

switch (msg.test_case())
{
    case protoTest::DemoMsg::kId:
        cout << msg.id() << endl; break;
    case protoTest::DemoMsg::kName:
        cout << msg.name() << endl; break;
    default:
        break;
 }

在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值