目录
- 1.字段规则
- 2.消息类型的定义与使用
- 1.定义
- 2.使用
- 3.enum类型
- 1.语法
- 2.定义时注意
- 3.代码
1.字段规则
- 消息的字段可以⽤下⾯⼏种规则来修饰:
singular
:消息中可以包含该字段零次或⼀次(不超过⼀次)- proto3语法中,字段默认使⽤该规则
repeated
:消息中可以包含该字段任意多次(包括零次),其中重复值的顺序会被保留- 可以理解为定义了⼀个数组
- 示例:表示一个通讯录里有多个人的信息
message Contacts {repeated PeopleInfo contacts = 1; }
2.消息类型的定义与使用
1.定义
- 在单个
.proto
⽂件中可以定义多个消息体,且⽀持定义嵌套类型的消息(任意多层)- 每个消息体中的字段编号可以重复
- 更新
contacts.proto
,可以将phone_number
提取出来,单独成为⼀个消息// -------------------------- 嵌套写法 ------------------------- syntax = "proto3"; package contacts;message PeopleInfo {string name = 1; int32 age = 2; message Phone {string number = 1;} } // -------------------------- ⾮嵌套写法 ------------------------ syntax = "proto3"; package contacts;message Phone {string number = 1; }message PeopleInfo {string name = 1; int32 age = 2; }
2.使用
- 消息类型可作为字段类型使用
syntax = "proto3"; package contacts;// 联系⼈ message PeopleInfo {string name = 1; int32 age = 2; message Phone {string number = 1; }repeated Phone phone = 3; }
- 可导入其他
.proto
文件的消息并使用:import
导入syntax = "proto3"; package contacts; import "phone.proto"; // 使⽤ import 将 phone.proto ⽂件导⼊进来message PeopleInfo {string name = 1; int32 age = 2; // 引⼊的⽂件声明了package,使⽤消息时,需要⽤ ‘命名空间.消息类型’ 格式 repeated phone.Phone phone = 3; }
- 注意:在proto3⽂件中可以导⼊proto2消息类型并使⽤它们,反之亦然
- 说明:
- 每个字段都有⼀个
clear_
⽅法,可以将字段重新设置回empty
状态 - 每个字段都有设置和获取的⽅法, 获取⽅法的⽅法名称与字段命名完全相同
- 但如果是消息类型的字段,其设置⽅法为
mutable_
⽅法,返回值为消息类型的指针,这类⽅法会为用户开辟好空间,可以直接对这块空间的内容进⾏修改mutable
-> 访问和修改消息字段中的嵌套消息
- 但如果是消息类型的字段,其设置⽅法为
- 对于使⽤
repeated
修饰的字段,也就是数组类型,pb为用户提供:add_
⽅法来新增⼀个值_size
⽅法来判断数组存放元素的个数
- 每个字段都有⼀个
3.enum类型
1.语法
- 语法:
enum Type {}
- 注意:
- 0值常量必须存在,且要作为第⼀个元素
- 这是为了与proto2的语义兼容:第⼀个元素作为默认值,且值为0
- 枚举类型可以在消息外定义,也可以在消息体内定义(嵌套)
- 枚举的常量值在32位整数的范围内
- 负值⽆效,所以不建议使⽤负值
- 0值常量必须存在,且要作为第⼀个元素
2.定义时注意
- 将两个"具有相同枚举值名称"的枚举类型放在单个
.proto
⽂件下测试时,编译后会报错:某某某常量已经被定义,所以这⾥要注意:- 同级(同层)的枚举类型,各个枚举类型中的常量不能重名
enum PhoneType {MP = 0;TEL = 1; } enum PhoneTypeCopy {MP = 0; // ERROR:MP 已经定义 }
- 单个
.proto
⽂件下,最外层枚举类型和嵌套枚举类型,不算同级enum PhoneTypeCopy {MP = 0; // ⽤法正确 }message Phone {string number = 1;enum PhoneType {MP = 0;TEL = 1;} }
- 多个
.proto
⽂件下,若⼀个⽂件引⼊了其他⽂件,且每个⽂件都未声明package
,每个proto⽂件中的枚举类型都在最外层,算同级// phone1.proto import "phone1.proto" enum PhoneType {MP = 0; // ERROR:MP 已经定义TEL = 1; }// phone2.proto enum PhoneTypeCopy {MP = 0; }
- 多个
.proto
⽂件下,若⼀个⽂件引⼊了其他⽂件,且每个⽂件都声明了package
,不算同级// phone1.proto import "phone1.proto" package phone1; enum PhoneType {MP = 0; // ⽤法正确TEL = 1; }// phone2.proto package phone2; enum PhoneTypeCopy {MP = 0; }
- 同级(同层)的枚举类型,各个枚举类型中的常量不能重名
3.代码
- 编译生成的CPP代码:
// 新⽣成的 PeopleInfo_Phone_PhoneType 枚举类 enum PeopleInfo_Phone_PhoneType : int {PeopleInfo_Phone_PhoneType_MP = 0,PeopleInfo_Phone_PhoneType_TEL = 1,PeopleInfo_Phone_PhoneType_PeopleInfo_Phone_PhoneType_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),PeopleInfo_Phone_PhoneType_PeopleInfo_Phone_PhoneType_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max() };// 更新的 PeopleInfo_Phone 类 class PeopleInfo_Phone final : public ::PROTOBUF_NAMESPACE_ID::Message { public:typedef PeopleInfo_Phone_PhoneType PhoneType;static inline bool PhoneType_IsValid(int value) {return PeopleInfo_Phone_PhoneType_IsValid(value);}template<typename T>static inline const std::string& PhoneType_Name(T enum_t_value) {...}static inline bool PhoneType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name, PhoneType* value) {...}// .contacts.PeopleInfo.Phone.PhoneType type = 2;void clear_type();::contacts::PeopleInfo_Phone_PhoneType type() const;void set_type(::contacts::PeopleInfo_Phone_PhoneType value); };
- 上述的代码中
- 对于在
.proto
⽂件中定义的枚举类型,编译⽣成的代码中会含有- 与之对应的枚举类型
- 校验枚举值是否有效的⽅法
_IsValid
- 以及获取枚举值名称的⽅法
_Name
- 对于使⽤了枚举类型的字段,包含设置和获取字段的⽅法,已经清空字段的⽅法
clear_
- 对于在