当前建议使用 proto3,Language Guide (proto3) 。
proto3 需要在文件开头声明语法版本为 proto3:
syntax = "proto3";
proto3 去掉了 required
和 optional
,保留了 repeated
,原因说明 why messge type remove ‘required,optional’?:
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1; // 不需要指定 required 或者 optional,proto3 全部当作 optional 处理
string title = 2;
repeated string snippets = 3;
}
提供了 一个 Any 类型:
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
repeated google.protobuf.Any details = 2;
}
其余部分基本继承了 proto2 的语法。
PLanguage Guide(proto2) 介绍了 Proto2 的用法。
field 的编号:
field 类型:
repeated int32 samples = 4 [packed = true];
用 reserverd 避免曾经使用过后来被删除的 field 的编号被再次使用:
message Foo {
reserved 2, 15, 9 to 11; // 使用编号
reserved "foo", "bar"; // 或者名称,但是编号和名称不同同时混用
}
enum Foo {
reserved 2, 15, 9 to 11, 40 to max; // 用 max 表示最大值
reserved "FOO", "BAR";
}
支持的类型:Scalar Value Types
double
float
int32
int64
uint32
uint64
sint32: 对负数的编码更高效
sint64: 对负数的编码更高效
fixed32:永远 4 字节,对应大于 2^28 的数值编码更高效
fixed64:永远 8 字节,对应大于 2^56 的数值编码更高效
sfixed32: 永远 4 字节
sfixed64: 永远 8 字节
bool:
string:UTF-8 或者 7-bit ASCII Text
bytes:
用 default 设置 optional field 缺失时的默认数值,如果未设置 default 使用类型默认值:
optional int32 result_per_page = 3 [default = 10];
enum 使用 32bit,使用 varint 编码,对负数编码效率低,不建议使用负数。
enum 可以独立定义,也可以在 message 内部定义:
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3 [default = 10];
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
optional Corpus corpus = 4 [default = UNIVERSAL];
}
import public
不支持 java,它的用途是让引用当前的文件,引用 import public 包含的文件
// new.proto
// All definitions are moved here
// old.proto
// This is the proto that all clients are importing.
import public "new.proto";
import "other.proto";
// client.proto
import "old.proto";
// You use definitions from old.proto and new.proto, but not other.proto
proto2 可以引用 proto3 的定义,proto3 不能引用 proto2 中的 enum。
嵌套定义的引用方法:
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
message SomeOtherMessage {
optional SearchResponse.Result result = 1;
}
group 不建议使用了,用嵌套定义替代 :
message SearchResponse {
repeated group Result = 1 { // group 不建议使用了
required string url = 2;
optional string title = 3;
repeated string snippets = 4;
}
}
更新接口定义注意事项 :
extensions 用来预留扩展字段,其它 proto 文件可以自主设定预留字段的 field:
message Foo {
// ...
extensions 100 to 199;
}
// 另一个 proto 文件,扩展 Foo:
extend Foo {
optional int32 bar = 126; // 扩展的 field 不能是 oneof、map
}
oneof 中的 field 不能使用 requried、optional、repeated,但是可以使用内部使用了这些修饰符的 message
message SampleMessage {
oneof test_oneof {
string name = 4; // 不能使用 requried、optional、repeated 修饰
SubMessage sub_message = 9; // SubMessage 内部的 field 可以用 requried、optional、repeated 修饰
}
}
map 的注意事项:
map 等价于下面的定义:
message MapFieldEntry {
optional key_type key = 1;
optional value_type value = 2;
}
repeated MapFieldEntry map_field = N;
package 声明文件的包名:
package foo.bar;
message Open { ... }
// 另一个 proto 文件:
message Foo {
...
required foo.bar.Open open = 1;
...
}
rpc 接口定义方法:
service SearchService {
rpc Search(SearchRequest) returns (SearchResponse);
}
option 是 proto 文件的配置项,google/protobuf/descriptor.proto 示例了所有 option 的用法。
option 分为file-level
、message-level
和 field-level
,分别在不同的位置使用。
file 级别的 option 用法:
option go_package = "google.golang.org/protobuf/types/descriptorpb";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
option csharp_namespace = "Google.Protobuf.Reflection";
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// descriptor.proto must be optimized for speed because reflection-based
// algorithms don't work during bootstrapping.
option optimize_for = SPEED;
message 级别的 option 用法:
message Foo {
option message_set_wire_format = true;
extensions 4 to max;
}
field 级别的 option 用法:
repeated int32 samples = 4 [packed = true];
optional int32 old_field = 6 [deprecated=true];
可以通过扩展 google.protobuf.XXXOptions 自定义 option:
import "google/protobuf/descriptor.proto";
extend google.protobuf.MessageOptions {
optional string my_option = 51234; // 自定义 message-level option
}
message MyMessage {
option (my_option) = "Hello world!";
}
代码生成命令,IMPORT_PATH 指定查找 proto 文件的路径:
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto
安装了 protobuf 插件,IntelliJ IDEA 还是不能识别 protobuf 的 import:
Protocol Buffer imports not recognized in Intellij中的方法有效: