Protocol Buffers 使用了一种中立、平台无关的语言来定义数据结构,使得不同编程语言、不同平台之间能够进行数据交互。Protocol Buffers 目前主要有 Proto2 和 Proto3 两个版本,Proto3 保持了与 Proto2 的一定程度的兼容性。但是,某些 Proto2 特性在 Proto3 中不再支持。
1. 标量类型
在 Protobuf 中,标量类型(Scalar Types)是指一些基本的数据类型,可以直接在 .proto
文件中定义并用于数据字段。这些类型对应于原生的简单数据类型,类似于编程语言中的整型、浮点型、布尔型等。
Document:https://protobuf.dev/programming-guides/proto3/#scalar
案例:在 protos 目录中创建 employee.proto 文件,定义 Employee 消息:
syntax = "proto3"; message Employee { // 姓名 string name = 1; // 年龄 int32 age = 2; // 薪资 double salary = 3; // 性别 bool gender = 4; }
注意:当创建数据字段时,每个字段都需要指定一个唯一的位置编号,用于区分不同的字段。
最后使用 protoc 编译器生成对应语言的操作代码:
protoc protos/employee.proto --python_out=output protoc protos/employee.proto --cpp_out=output
2. 复杂类型
在 message 中也可以定义较为复杂的类型,例如:
- 枚举类型:枚举类型用于定义一组命名常量
- 嵌套消息:在一个消息中嵌套另一个消息
- 重复字段:表示一个字段可以出现零次或多次,可以理解为动态数组
- 映射字段:表示键值对的集合
案例:在 protos 目录中创建 developer.proto 文件,定义 Developer 消息:
syntax = "proto3"; message Other { int32 v1 = 1; int32 v2 = 2; } enum Week { // 第一个枚举项的值必须为 0,在 proto2 中没有此限制,这是因为对于枚举类型默认值是 0 // 后续的枚举项值可以是任意的、不重复的 Mon = 0; Tue = 3; Wed = 4; Thu = 5; Fri = 6; Sat = 7; Sun = 8; } message Developer { string name = 1; Week week = 2; repeated int32 list = 3; map<string, int32> map = 4; Other oher = 5; }
执行如下命令生成对应语言的操作代码:
protoc protos/developer.proto --cpp_out=output
注意:message 允许嵌套定义,即:message 中嵌套另外一个 message。在 protos 目录中创建 nested.proto 文件,定义 Developer 消息:
syntax = "proto3"; message Nested { string name = 1; map<string, int32> teles = 2; message Other { int32 v1 = 1; int32 v2 = 2; } Other other = 3; }
protoc protos/nested.proto --cpp_out=output
3. import 用法
import
指令允许在 Protobuf 中将一个 .proto 文件中的定义引入到另一个 .proto 文件中,以便在后者中使用前者中定义的消息类型、枚举类型等。
这种组织方式有助于管理大型的 .proto 定义,使得可以将不同的消息类型分别定义在不同的文件中,并通过 import
将它们组合在一起。import
指令通常位于文件顶部,其语法类似于其他编程语言中的导入或引用语句。
案例:在 protos 目录中创建 specialist.proto 文件,定义 Specialist 消息:
syntax = "proto3"; // 导入 employee.proto 文件 import "protos/employee.proto"; message Specialist { string name = 1; int32 age = 2; // 使用其他 employee.proto 定义的数据类型 Employee emp = 3; }
执行如下命令生成对应语言的操作代码:
protoc protos/specialist.proto --cpp_out=output
4. package 用法
在 Protobuf 中,package
关键字用于定义一个命名空间,用于组织和管理定义的消息类型。它有助于避免命名冲突,并使得代码更加清晰和易于维护。
在 protos 目录中创建 common1.proto 文件,在 foo.bar1 中定义 Information 消息:
syntax = "proto3"; package foo.bar1; message Information { string info_content1 = 1; string info_content2 = 2; }
在 protos 目录中创建 common2.proto 文件,在 foo.bar2 中定义 Information 消息:
syntax = "proto3"; package foo.bar2; message Information { int32 info_id1 = 1; int32 info_id2 = 2; }
在 protos 目录中创建 common.proto 文件,定义 Message 消息:
syntax = "proto3"; import "protos/common1.proto"; import "protos/common2.proto"; message Message { // 通过包名访问 Message 类型 foo.bar1.Information info1 = 1; foo.bar2.Information info2 = 2; }
protoc protos/common.proto --cpp_out=output