当前位置: 首页 > news >正文

Google第三方库详解------ProtoBuf详解 + 样例(5万字详解!)

目录

前言:

提示:

插件

入门:

ProtoBuf普通字段类型:

编译命令:

序列化与反序列化:

Proto3语法:

字段规则:数组类型

应用

将通讯录数据序列化后写入文件

工具介绍:hexdump

将文件数据反序列化到类中:

ProtoBuf命令选项:

Decode选项:

Proto3语法:

字段规则:enum类型

应用:

Proto3语法:

字段规则:Any类型:

any的相关接口介绍:

应用:

Proto3语法:

字段规则:oneof类型:

应用:

Proto3语法:

字段规则:map类型:

应用:

Proto3语法:

字段规则:默认值:

Proto3语法:

字段规则:更新消息:

字段规则:reserved:

Proto3语法:

字段规则:option:


前言:

提示:

安装等过程在此处就不阐述,请读者自行查阅:

代码演示环境:ubuntu22.04云服务器

插件

vscode支持ProtoBuf语法高亮的插件:vscode-proto

入门:

1.首先创建一个.proto文件
2.声明语法指定行
syntax = "proto3";
3.声明命名空间
package contacts;
4.定义一个message消息
message PeopleInfo
{
    string _name = 1;
    int32 _age = 2;
}
//其中,1和2都是ProtoBuf用来标识字段唯一性的ID,同一个message中id不能相同也不能缺省;
//ID范围 =  {1,2^29-1],其中19000~19999之间的数不可用;

ProtoBuf普通字段类型:

//ProtoBuf类型                                                                        
double 
double 
float 
float     
int32 :使⽤变⻓编码[1]。负数的编码效率较低⸺若字段可能为负值,应使⽤ sint32 代替。 
int64 :使⽤变⻓编码[1]。负数的编码效率较低⸺若字段可能为负值,应使⽤ sint64 代替。 
uint32:使⽤变⻓编码[1]。 
uint64 :使⽤变⻓编码[1]。 
sint32 :使⽤变⻓编码[1]。符号整型。负值的编码效率⾼于常规的 int32 类型。 
sint64 :使⽤变⻓编码[1]。符号整型。负值的编码效率⾼于常规的 int64 类型。 
fixed32: 定⻓ 4 字节。若值常⼤于2^28 则会⽐ uint32 更⾼效。 
fixed64 :定⻓ 8 字节。若值常⼤于2^56 则会⽐ uint64 更⾼效。 
sfixed32:定⻓ 4 字节。 
sfixed64:定⻓ 8 字节。 
bool类型
string:包含 UTF-8 和 ASCII 编码的字符串,⻓度不能超过 2^32 。 
bytes:可包含任意的字节序列但⻓度不能超过 2^32 。 

编译命令:

1.编译当前路径下的.protoc文件
    protoc --cpp_out=要保存的路径名 依赖的.proto文件
    例如:protoc --cpp_out=. contact.proto
2.编译指定路径下的.protoc文件
    protoc -I .protoc文件所处路径 --cpp_out=要保存的路径名 依赖的.proto文件

序列化与反序列化:

注意:ProtoBuf序列化后不是文本序列,而是二进制序列!
序列化接口:以Serialize开头
反序列化接口:以Parse开头

#include <iostream>
#include <string>
//#include"ProtoBuf编译后的头文件.h"
#include "contacts.pb.h"

int main()
{
    std::string data;
    //序列化
    {
        contacts::PeopleInfo ple;
        ple.set_name("张三");
        ple.set_age(20);
        // 序列化
        if (!ple.SerializeToString(&data))
        {
            std::cout << "序列化联系人信息失败!" << std::endl;
            return -1;
        }
        std::cout << "Serialized str = " << data << std::endl;
    }
    //反序列化
    {
        contacts::PeopleInfo ple;
        if(!ple.ParseFromString(data))
        {
            std::cout<<"反序列化失败!"<<std::endl;
            return -2;
        }
        std::cout<<"反序列化成功!"<<std::endl<<
        "姓名: "<<ple.name()<<std::endl<<
        "年龄:"<<ple.age()<<std::endl;
    }
    return 0;
}

Makefile文件:

Main:Main.cpp contacts.pb.cc
    g++ -o $@ $^ -std=c++11 -lprotobuf
.PHONY:clean
clean:
    rm -f Main

Proto3语法:

字段规则:数组类型

1.数组类型:repeated
//样例1:
message PeopleInfo
{
    string name = 1;
    int32 age = 2;
    repeated string phone_numbers = 3;
}
//也可以是message类型的数组
message PhoneNumbers
{
    string phone = 1;
}
message PeopleInfo
{
    string name = 1;
    int32 age = 2;
    repeated PhoneNumbers phones = 3;
}

在一个.proto文件中使用另外一个.proto文件的message:

//以phone.proto和contacts.proto为例
//phone.proto
message PhoneNumbers
{
    string phone = 1;
}
//contacts.proto
syntax = "proto3";
package contacts;
import "phone.proto";

message PeopleInfo
{
    string name = 1;
    int32 age = 2;
    repeated phone.PhoneNumbers phones = 3;
}
/*注意,如果外部的.proto文件中存在命名空间,则在本文件inport引入后,需要指定空间(空间名+.)
才能使用message*/

应用

将通讯录数据序列化后写入文件

接口介绍:以上述.proto文件编译后的文件为例:

1.add_contacts()
作用:返回一块新的contacts数组中的空间地址用以用户填充相关字段,作用类似于push_back
2.add_phones()
作用:返回一块新的contacts数组中phone数组中的空间地址用以用户填充相关字段,作用类似于push_back
3.cin.ignore()
作用:cin的ignore函数可以用来清空cin的缓冲区,传递一个足够大的参数和一个终止符即可,cin会根据传递的大小和终止符来清空包括终止符在内的缓冲区数据

code:

#include <iostream>
#include <fstream>
#include <string>
#include "contacts.pb.h"

void AddContact(contacts::PeopleInfo *con)
{
    std::cout<<"---------------新增联系人---------------"<<std::endl;
    std::cout<<"输入联系人姓名: ";
    std::string name;
    std::getline(std::cin, name);
    con->set_name(name);
    int age = 0;
    std::cout<<"输入联系人年龄: ";
    std::cin >> age;
    con->set_age(age);
    // 清空cin缓冲区
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // 新增电话
    for(int i = 1;true;i++)
    {
        std::cout<<"---请输入该联系人的电话"<<i<<"(只输入空格表示完成)"<<": ";
        std::string number;
        std::getline(std::cin,number);
        if(number.size() == 0) break;
        contacts::PeopleInfo_Phone* phone = con->add_phones();
        phone->set_phone(number);
    }
     std::cout<<"---------------添加联系人成功---------------"<<std::endl;
}
int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "contacts.bin is not exist,create new contacts.bin" << std::endl;
    }
    else if (!cons.ParseFromIstream(&in))
    {
        std::cout << "Parse contact info error!" << std::endl;
        in.close();
        return -1;
    }

    AddContact(cons.add_contacts());

    // 序列化写入文件
    std::ofstream out("contacts.bin", std::ios::trunc | std::ios::binary);
    if (!out.is_open())
    {
        std::cout << "write file error!" << std::endl;
        return -2;
    }
    if (!cons.SerializePartialToOstream(&out))
    {
        std::cout << "序列化失败!" << std::endl;
        return -3;
    }
    
    in.close();
    out.close();
    return 0;
}

工具介绍:hexdump

将二进制数据转换为十六进制:

指令:hexdump -C 二进制文件

将文件数据反序列化到类中:

#include <iostream>
#include <fstream>
#include "contacts.pb.h"

int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::in | std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "open contacts.bin error!" << std::endl;
        return -1;
    }
    else if (!cons.ParsePartialFromIstream(&in))
    {
        std::cout << "反序列化失败!" << std::endl;
        return -1;
    }
    
    for(int i = 0;i<cons.contacts_size();i++)
    {
        std::cout<<"-------------------------------"<<std::endl;
         std::cout<<"------------联系人-------------"<<std::endl;
        auto people = cons.contacts(i);
        std::cout<<"姓名: ";
        std::cout<<people.name()<<std::endl;
        std::cout<<"年龄: "<<people.age()<<std::endl;
        std::cout<<"-----------联系电话-------------"<<std::endl;
        for(int i = 0;i<people.phones_size();i++)
        {
            std::cout<<(people.phones(i)).phone()<<std::endl;
        }
        std::cout<<"----------- 联系人-------------"<<std::endl;
         std::cout<<"-----------------------------"<<std::endl;
    }
    in.close();
    return 0;
}

ProtoBuf命令选项:

查询ProtoBuf指令手册
    指令:protoc -h

Decode选项:

从标准输入流中将二进制数据转换成文本类型数据,可以将stdin重定向到某个二进制类型文件:

protoc --decode=命名空间.指定的message类型的变量名 指定的.proto文件 < 指定的二进制文件

Proto3语法:

字段规则:enum类型

枚举类型中,第一个枚举的变量值一定要以0开头,枚举类型中的变量不能设置为负值,且只能是32位数字:

注意:1.同一个文件中的枚举类型中的变量名不能相同;
2.在多个.proto文件中,如果枚举类型名字相同,需要申明一下package
3.import一个.proto文件后,如果不适用其中的任何东西,编译时会有warning
syntax = "proto3";
package contacts;

message PeopleInfo
{
    string name = 1;
    int32 age = 2;
    message Phone 
    {
        string number = 1;
        enum PhoneType
        {
            HP = 0;
            TEL = 1;
        }
        PhoneType type = 2;
   }
   repeated Phone phones = 3;
}

message Contacts
{
    repeated PeopleInfo contacts = 1;
}

应用:

接口介绍:
    1.set_type(type)
    作用:设置类型,在上述例子中参数为:contacts::PeopleInfo_Phone_PhoneType中的常量
    2.PhoneType_Name(type)
    作用:将传递的参数type转换成字符串返回
    3.Phones(int index)
    作用:返回数组中index下标对应的元素
//write.cc
#include <iostream>
#include <fstream>
#include <string>
#include "contacts.pb.h"

void AddContact(contacts::PeopleInfo *con)
{
    std::cout<<"---------------新增联系人---------------"<<std::endl;
    std::cout<<"输入联系人姓名: ";
    std::string name;
    std::getline(std::cin, name);
    con->set_name(name);
    int age = 0;
    std::cout<<"输入联系人年龄: ";
    std::cin >> age;
    con->set_age(age);
    // 清空cin缓冲区
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // 新增电话
    for(int i = 1;true;i++)
    {
        std::cout<<"---请输入该联系人的电话"<<i<<"(只输入空格表示完成)"<<": ";
        std::string number;
        std::getline(std::cin,number);
        if(number.size() == 0) break;
        contacts::PeopleInfo_Phone* phone = con->add_phones();
        // phone->set_phone(number);
        phone->set_number(number);
        std::cout<<"--请输入该联系人电话类型:|1.HP--2.TEL|-----: ";
        int type;
        std::cin>>type;
        switch(type)
        {
            case 1: 
                phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_HP);
                break;
            case 2:
                phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);
                break;
        }
    }
     std::cout<<"---------------添加联系人成功---------------"<<std::endl;
}
int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "contacts.bin is not exist,create new contacts.bin" << std::endl;
    }
    else if (!cons.ParseFromIstream(&in))
    {
        std::cout << "Parse contact info error!" << std::endl;
        in.close();
        return -1;
    }

    AddContact(cons.add_contacts());

    // 序列化写入文件
    std::ofstream out("contacts.bin", std::ios::trunc | std::ios::binary);
    if (!out.is_open())
    {
        std::cout << "write file error!" << std::endl;
        return -2;
    }
    if (!cons.SerializePartialToOstream(&out))
    {
        std::cout << "序列化失败!" << std::endl;
        return -3;
    }
    
    in.close();
    out.close();
    return 0;
}
//read.cc
#include <iostream>
#include <fstream>
#include "contacts.pb.h"

int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::in | std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "open contacts.bin error!" << std::endl;
        return -1;
    }
    else if (!cons.ParsePartialFromIstream(&in))
    {
        std::cout << "反序列化失败!" << std::endl;
        return -1;
    }
    
    for(int i = 0;i<cons.contacts_size();i++)
    {
        std::cout<<"-------------------------------"<<std::endl;
         std::cout<<"------------联系人-------------"<<std::endl;
        auto people = cons.contacts(i);
        std::cout<<"姓名: ";
        std::cout<<people.name()<<std::endl;
        std::cout<<"年龄: "<<people.age()<<std::endl;
        std::cout<<"-----------联系电话-------------"<<std::endl;
        for(int i = 0;i<people.phones_size();i++)
        {
            contacts::PeopleInfo_Phone phone = people.phones(i);
            std::cout<<phone.number()<<std::endl;
            std::cout<<"电话类型: "<<phone.PhoneType_Name(phone.type())<<std::endl;
        }
        std::cout<<"----------- 联系人-------------"<<std::endl;
         std::cout<<"-----------------------------"<<std::endl;
    }
    in.close();
    return 0;
}

Proto3语法:

字段规则:Any类型:

首先,先查看ProtoBuf库的路径位置:
/usr/local/include/google/protobuf/
在这个路径下存在一个any.ptoto文件
//1,引入any.proto
import "google/protobuf/any.protoc";
syntax = "proto3";
package contacts;

import "google/protobuf/any.proto";

//地址信息
message Address{
    string util_address = 1;
    string home_address = 2;
}

message PeopleInfo{
    string name = 1;
    int32 age = 2;
    message Phone 
    {
        string number = 1;
        enum PhoneType
        {
            MP = 0;
            TEL = 1;
        }
        PhoneType type = 2;
   }
   repeated Phone phones = 3;
   google.protobuf.Any data = 4;
}

message Contacts{
    repeated PeopleInfo contacts = 1;
}

any的相关接口介绍:

any在google::protobuf::Any::中,即定义:google::protobuf::Any::变量名
1.mutablek开头的接口()
作用:返回一个开辟好的any空间
在上述.proto文件编译的前提下:接口名为:mutablek_data();
2.PackFrom(message&)
作用:将一个message类型的对象存储到any对象中
3.UnpackTo(message*)
作用:将一个any对象中存储的message对象提取出来;
4.has_data()
作用:判断内部的any对象是是否有数据,有则返回true.反之false

应用:

//为联系人信息增加地址信息
//write.cc
#include <iostream>
#include <fstream>
#include <string>
#include "contacts.pb.h"

void AddContact(contacts::PeopleInfo *con)
{
    std::cout<<"---------------新增联系人---------------"<<std::endl;
    std::cout<<"输入联系人姓名: ";
    std::string name;
    std::getline(std::cin, name);
    con->set_name(name);
    int age = 0;
    std::cout<<"输入联系人年龄: ";
    std::cin >> age;
    con->set_age(age);
    // 清空cin缓冲区
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // 新增电话
    for(int i = 1;true;i++)
    {
        std::cout<<"---请输入该联系人的电话"<<i<<"(只输入空格表示完成)"<<": ";
        std::string number;
        std::getline(std::cin,number);
        if(number.size() == 0) break;
        contacts::PeopleInfo_Phone* phone = con->add_phones();
        // phone->set_phone(number);
        phone->set_number(number);
        std::cout<<"--请输入该联系人电话类型:|1.移动电话--2.固定电话|-----: ";
        int type;
        std::cin>>type;
        std::cin.ignore(256,'\n');
        switch(type)
        {
            case 1: 
                phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP);
                break;
            case 2:
                phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);
                break;
        }
        //填充地址信息
        contacts::Address address;
        std::cout<<"请输入工作单位地址(不填请按空格结束): ";
        std::string util_address;
        std::getline(std::cin,util_address);
        address.set_util_address(util_address);
        std::string home_address;
        std::cout<<"请输入家庭地址(不填请按空格结束): ";
        std::getline(std::cin,home_address);
        address.set_home_address(home_address);
        //people中的mutable_data方法会返回一个开辟好的any对象地址
        google::protobuf::Any* any = con->mutable_data();
        //将message信息解析到any中
        any->PackFrom(address);
    }
     std::cout<<"---------------添加联系人成功---------------"<<std::endl;
}
int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "contacts.bin is not exist,create new contacts.bin" << std::endl;
    }
    else if (!cons.ParseFromIstream(&in))
    {
        std::cout << "Parse contact info error!" << std::endl;
        in.close();
        return -1;
    }

    AddContact(cons.add_contacts());

    // 序列化写入文件
    std::ofstream out("contacts.bin", std::ios::trunc | std::ios::binary);
    if (!out.is_open())
    {
        std::cout << "write file error!" << std::endl;
        return -2;
    }
    if (!cons.SerializePartialToOstream(&out))
    {
        std::cout << "序列化失败!" << std::endl;
        return -3;
    }
    
    in.close();
    out.close();
    return 0;
}
//read.cc
#include <iostream>
#include <fstream>
#include "contacts.pb.h"

int main()
{
    contacts::Contacts cons;
    std::ifstream in("contacts.bin", std::ios::in | std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "open contacts.bin error!" << std::endl;
        return -1;
    }
    else if (!cons.ParsePartialFromIstream(&in))
    {
        std::cout << "反序列化失败!" << std::endl;
        return -1;
    }

    for (int i = 0; i < cons.contacts_size(); i++)
    {
        std::cout << "------------联系人--------------" << std::endl;
        std::cout << "-------------------------------" << std::endl;
        auto people = cons.contacts(i);
        std::cout << "姓名: ";
        std::cout << people.name() << std::endl;
        std::cout << "年龄: " << people.age() << std::endl;
        std::cout << "-----------联系电话-------------" << std::endl;
        for (int i = 0; i < people.phones_size(); i++)
        {
            contacts::PeopleInfo_Phone phone = people.phones(i);
            std::cout << phone.number() << std::endl;
            std::cout << "电话类型: " << phone.PhoneType_Name(phone.type()) << std::endl;
        }
        if (people.has_data())
        {
            std::cout << "------------地址----------------" << std::endl;
            google::protobuf::Any any = people.data();
            contacts::Address address;
            any.UnpackTo(&address);
            std::cout << "工作单位地址: " << address.util_address() << std::endl;
            std::cout << "家庭地址: " << address.home_address() << std::endl;
            std::cout << "--------------------------------" << std::endl;
            std::cout << "----------- 联系人--------------" << std::endl;
        }
        else
        {
            std::cout << "any is not setting!" << std::endl;
        }
    }
    in.close();
    return 0;
}

Proto3语法:

字段规则:oneof类型:

oneof类型是多选一的
//contacts.proto
例如用来定义:
 oneof other_contact{
        string qq = 5;
        string wechat = 6;
   }
//contacts。proto文件
syntax = "proto3";
package contacts;

import "google/protobuf/any.proto";

//地址信息
message Address{
    string util_address = 1;
    string home_address = 2;
}

message PeopleInfo{
    string name = 1;
    int32 age = 2;
    message Phone {
        string number = 1;
        enum PhoneType
        {
            MP = 0;
            TEL = 1;
        }
        PhoneType type = 2;
   }
   repeated Phone phones = 3;
   google.protobuf.Any data = 4;
   //其他联系方式
   oneof other_contact{
        string qq = 5;
        string wechat = 6;
   }
}

message Contacts{
    repeated PeopleInfo contacts = 1;
}

应用:

接口解释:
1.通过oneof设置的字段,只能填写一个,即多选一模式,以最后一次填写的字段为准
2.other_contact_case()
作用:返回内部被设置的那个字段的常量。类型为contacts::PeopleInfo::OtherContactCase
用于读取文件时判断哪个字段是有效的。
//write.cc
 std::cout << "请输入其他联系方式->|1.qq---2.微信|: ";
        int op = 0;
        std::cin >> op;
        std::cin.ignore(256, '\n');
        std::string other_contact;
        switch (op)
        {
        case 1:
            std::cout << "请输入qq号: ";
            std::getline(std::cin, other_contact);
            con->set_qq(other_contact);
            break;
        case 2:
            std::cout << "请输入微信号: ";
            std::getline(std::cin, other_contact);
            con->set_wechat(other_contact);
            break;
        default:
            std::cout<<"未知错误!"<<std::endl;
            break;
        }
//Read.cc
    // 查看其他联系方式
        contacts::PeopleInfo::OtherContactCase other_con = people.other_contact_case();
        switch (other_con)
        {
        case contacts::PeopleInfo::OtherContactCase::kQq:
            std::cout << "QQ: " << people.qq() << std::endl;
            break;
        case contacts::PeopleInfo::OtherContactCase::kWechat:
            std::cout << "微信: " << people.wechat() << std::endl;
            break;
        default:
            std::cout << "未知错误!" << std::endl;
            break;
        }

Proto3语法:

字段规则:map类型:

1.map字段不能被repeated修饰

//.proto文件
syntax = "proto3";
package contacts;

import "google/protobuf/any.proto";

//地址信息
message Address{
    string util_address = 1;
    string home_address = 2;
}

message PeopleInfo{
    string name = 1;
    int32 age = 2;
    message Phone 
    {
        string number = 1;
        enum PhoneType
        {
            MP = 0;
            TEL = 1;
        }
        PhoneType type = 2;
   }
   repeated Phone phones = 3;
   google.protobuf.Any data = 4;
   //其他联系方式
   oneof other_contact{
        string qq = 5;
        string wechat = 6;
   }
   //备注信息
   map<string,string> remarks = 7;
}

message Contacts{
    repeated PeopleInfo contacts = 1;
}

应用:

接口介绍:
1.mutable_remarks()
作用:返回一块开辟好的map空间地址
2.insert()
作用:新增map类型的数据--即key-val键值对
注意:不能使用make_pair,可以使用{key,val}插入
3.remarks()
作用:获取map对象
4.begin()和cbegin()
作用:迭代器,用法和c++的map一致
//write.cc
  std::cout<<"请输入该联系人的备注信息: ";
        google::protobuf::Map<std::string, std::string>* remark = con->mutable_remarks();
        for(int i = 1;;i++)
        {
            std::cout<<"请输入备注标题"<<i<<"(按下空格结束): ";
            std::string key;
            std::getline(std::cin,key);
            if(key.size() == 0) break;
            std::cout<<"请输入备注内容"<<"(按下空格结束): ";
            std::string val;
            std::getline(std::cin,val);
            if(val.size() == 0) break;
            remark->insert({key,val});
        }
//Read.cc
std::cout<<"---------查看备注信息-----------"<<std::endl;
auto remark = people.remarks();
for(int i = 0;i<people.remarks_size();i++)
{
     std::cout<<"备注标题"<<i+1<<": "<< ((remark.begin())->first)<<std::endl;
     std::cout<<"备注内容: "<<((remark.begin())->second)<<std::endl;
}
std::cout<<"----------------------------------"<<std::endl;          

Proto3语法:

字段规则:默认值:

//默认值 
1.反序列化消息时,如果被反序列化的⼆进制序列中不包含某个字段,反序列化对象中相应字段时,就 
会设置为该字段的默认值。不同的类型对应的默认值不同: 
2.对于字符串,默认值为空字符串。 
3.对于字节,默认值为空字节。 
4.对于布尔值,默认值为 false。 
5.对于数值类型,默认值为 0。 
6.对于枚举,默认值是第⼀个定义的枚举值, 必须为 0。  
7.对于消息字段,未设置该字段。它的取值是依赖于语⾔。 
8.对于设置了 repeated 的字段的默认值是空的( 通常是相应语⾔的⼀个空列表 )。 
9.对于 消息字段 、 oneof字段 和 any字段 ,C++ 和 Java 语⾔中都有 has_ ⽅法来检测当前字段 
是否被设置。 
注意:proto3语法下,标量数据类型没有生成has_方法,保证对于标量字段用户一定要手动初始化!

Proto3语法:

字段规则:更新消息:

1.如果现有的消息类型已经不再满⾜我们的需求,例如需要扩展⼀个字段,在不破坏任何现有代码的情 
况下更新消息类型⾮常简单。遵循如下规则即可: 
2.禁⽌修改任何已有字段的字段编号。 
3.若是移除⽼字段,要保证不再使⽤移除字段的字段编号。正确的做法是保留字段编号 
(reserved),以确保该编号将不能被重复使⽤。不建议直接删除或注释掉字段。 
4.int32, uint32, int64, uint64 和 bool 是完全兼容的。可以从这些类型中的⼀个改为另⼀个, 
⽽不破坏前后兼容性。若解析出来的数值与相应的类型不匹配,会采⽤与 C++ ⼀致的处理⽅案 
(例如,若将 64 位整数当做 32 位进⾏读取,它将被截断为 32 位)。 
5.sint32 和 sint64 相互兼容但不与其他的整型兼容。 
6.string 和 bytes 在合法 UTF-8 字节前提下也是兼容的。 
7.bytes 包含消息编码版本的情况下,嵌套消息与 bytes 也是兼容的。 
8.fixed32 与 sfixed32 兼容, fixed64 与 sfixed64兼容。 
9.enum 与 int32,uint32, int64 和 uint64 兼容(注意若值不匹配会被截断)。但要注意当反序 
列化消息时会根据语⾔采⽤不同的处理⽅案:例如,未识别的 proto3 枚举类型会被保存在消息 
中,但是当消息反序列化时如何表⽰是依赖于编程语⾔的。整型字段总是会保持其的值。 
10.oneof:将⼀个单独的值更改为 新 oneof 类型成员之⼀是安全和⼆进制兼容的。 
11.若确定没有代码⼀次性设置多个值那么将多个字段移⼊⼀个新 oneof 类型也是可⾏的。 
12.将任何字段移⼊已存在的 oneof 类型是不安全的。

字段规则:reserved:

1.reserved修饰的编号不能被使用!
如果要删除一个已有的消息字段,不要使用其对应的字段编号,用reserved修饰即可
//例子:
    reserved 1;
    int age = 1;
此时编译不被允许!
2.reserved可以用来修饰字段名
//例子:
     reserved "age";
     int32 age = 2;//要删除的字段
 此时编译不被允许!
3.reserved可以用来修饰大量数字
写法1:
    reserved 1,2,3,...;
写法2:
    reserved 100 to 200;
连续修饰字段名可以用逗号分隔开

Proto3语法:

字段规则:option:

本质是影响protobuf的编译功能

1.选项1:SPEEDZ:速度最快,但是占用空间更大
2.选项2:CODE_SIZE:速度最慢,空间更小,适用于包含大量的.proto文件中使用
3.选项3:LITE_RUNTIME:阉割版protobuf,仅仅提供序列化和反序列化功能+encode
4.选项4:allow_alias:允许将相同的常量值赋值给相同的枚举常量值
option allow_alias = true;

done

相关文章:

  • C#实现Modbus TCP 通讯测试软件
  • vue passive 修饰符使用场景
  • Python中的转义字符
  • MongoDB#常用脚本
  • Vulhub靶机 Apache Druid(CVE-2021-25646)(渗透测试详解)
  • 基于keepalived的Nginx高可用架构
  • 游戏引擎学习第119天
  • 【前端进阶】05 单线程的JavaScript如何管理任务的
  • Baklib企业CMS智能元数据与协作管理实践
  • 超级详细Spring AI运用Ollama大模型
  • 【CentOS7】安装MinIO
  • P1036 [NOIP 2002 普及组] 选数(dfs+素数筛选)
  • forge-1.21.x模组开发(一)注册方块和物品
  • Vue学习教程-15自定义指令
  • python 使用知识点 pyinstaller 虚拟环境打包
  • Java 18~20 新特性
  • Transformers快速入门-学习笔记
  • 一个基本的pyside6项目模板demo
  • Linux 命令大全完整版(06)
  • 【并发编程】线程池任务抛异常会怎么样?
  • “70后”通化市委书记孙简已任吉林省政府领导
  • 《深化养老服务改革发展的大湾区探索》新书将于今年6月出版
  • 证监会发布上市公司信披豁免规定:明确两类豁免范围、规定三种豁免方式
  • 上海发布一组人事任免信息:钱晓、翁轶丛任市数据局副局长
  • 四川公布一起影视盗版案例:1个网站2人团伙盗售30多万部
  • 胃病、闭经、湿疹、失明:藏在疾病后的情绪问题