一: 消息类型定义
syntax = "proto3"; //首先指定版本 proto3
// message 关键字用于定义消息,需要指定消息类型的名称。
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
应该为每个字段分配唯一的字段序号 ( query ) ,用于在二进制编码中标识该字段。序号范围1-15会消耗1个字节的存储,16-2047 会消耗2个字节。因此应该将常用的字段分配1-15字段序号。编号全部的范围是1到2^29-1,其中19000到19999是 proto编译器保留序号,不要使用。
消息的字段分为单一和重复两种规则:
单一 Singular,proto3 中字段的默认规则。一个消息中仅可以包含0或1个该字段,就是字段不能重复。
重复的 repeated,该规则说明此字段可以重复多次(包含0次)。重复值的顺序是保留的。
message SearchRequest {
// 同上略
repeated string keywords = 4
}
二: 标量类型
标量类型 : 一个值只代表一个数据
变长编码 : 省空间 , 但是编码效率低
定长编码 : 编码效率高 , 浪费空间
解析消息时,如果编码的消息不包含特定元素,则解析对象中的相应字段将设置为该字段的默认值。这些默认值是基于类型的:
字符串:默认值为空字符串。
字节:默认值为空字节。
布尔值:默认值为 false。
数字类型:默认值为零。
枚举:默认值是第一个定义的枚举值,必须为 0。
消息字段:未设置该字段。它的确切值取决于语言。有关详细信息,请参阅生成的代码指南。
重复字段的默认值为空(通常是相应语言的空列表)。
三: 枚举值
message SearchRequest {
// 定义枚举类型
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
// 用枚举类型定义字段
Corpus corpus = 4;
}
枚举值列表的第一常量值必须为 0,这样可以更好的处理默认值。(也为了向下兼容)
也可以为同一个枚举值分配不同的常量,称为别名。需要使用选项 option allow_alias = true
来启用别名设置:
message MyMessage1 {
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
// 开启枚举别名可以让枚举变量指向同一个值
STARTED = 1;
RUNNING = 1;
}
}
四: 保留值
当某些字段不再使用时,例如更新消息类型时移除了某些字段,为了防止其他人重新使用了之前的字段名或字段序号而导致逻辑混乱的问题,可以把这些不用的字段设置为保留字段,关键字 reserved
用来设置:
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
五: 使用其他消息类型
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
可以将不同类型的消息定义在不同的 .proto 文件中,需要时导入进来:
import "myproject/other_protos.proto";
六: 未知字段
最初,proto3 消息在解析过程中总是丢弃未知字段
在 3.5 及更高版本中,未知字段在解析期间保留并包含在序列化输出中。
想要不出现位置字段 , 就应该让 C 端和 S端保持数据同步
七: Any
Any 消息类型允许您将消息用作嵌入类型,而无需定义它们的 .proto。 Any 包含作为 Bytes
的任意序列化消息,以及充当全局唯一标识符并解析为该消息类型的 URL。要使用 Any 类型,您需要导入 google/protobuf/any.proto。
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
repeated google.protobuf.Any details = 2;
}
八: Oneof
如果有一条包含多个字段的消息,并且最多同时设置一个字段,可以强制执行此行为并使用 oneof 功能节省内存。
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
九: Map
protocol buffers 提供了 Map 作为映射数据的类型 :
key 是 string类型 , Project 是 Message 类型
map<string, Project> projects = 3;
十: Package
您可以将可选的 package
说明符添加到 .proto 文件中,以防止协议消息类型之间的名称冲突。
package foo.bar;
message Open { ... }
在 GO 中,该软件包被用作 GO 软件包名称,除非您在 .proto 文件中明确提供 option go_package
。
十一: 服务定义
如果您想在 RPC( 远程过程调用 )系统中使用您的消息类型,您可以在 .proto 文件中定义一个 RPC 服务接口,并且协议缓冲区编译器将以您选择的语言生成服务接口代码和存根。因此,例如,如果您想使用获取 SearchRequest 并返回 SearchResponse 的方法定义 RPC 服务,您可以在 .proto 文件中定义它,如下所示:
service SearchService {
rpc Search(SearchRequest) returns (SearchResponse);
}
十二: 选项
.proto
文件中支持定义选项。全部的选项定义在 google/protobuf/descriptor.proto
中。
例如: 我们使用 option go_package
选项来控制生成的 go 代码所在的 package
protocol buffer 对于 Java 和 C++ 选项提供的比较多
评论区