定义 Message 类型, 例子如下:
syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; // Which page number do we want? int32 result_per_page = 3; // Number of results to return per page. }
说明:
1、proto3
格式的必须第一行指明版本号, syntax = "proto3";
2、所有的字段都是 Scalar Value Types
3、象上面看到的,所有的字段定义都有一个唯一的数字标签,这些数字标签用来标识在消息二进制序列化时的顺序信息,序列化后,1~15占一个字节,16~2047占两个字节。(字段的类型和识别号码放在一起,下面可以看到 Scalar Value Types有15种,再加上标识号码, 所以只能 1-15 占一个字节, 16以上2个字节)
所以你要注意,用1-15标识频繁出现的元素。 标识号码最小 1, 最大 is 229 - 1, 或者 536,870,911, 其中要排除 19000 到19999 这段保留段。
Scalar Value Types
在 proto 文件和各种语言中对应的类型关系如下图:
这些类型的默认值如下:
- string 空字符串
- bytes 空 bytes
- bool 默认flase
- 数字类型 默认 0
- 枚举类型 默认第一个值, 而且第一个的数字编码必须是 0
- message fields 默认 null
- repeated 的字段默认是 null, 空的列表。
带枚举的一个message 例子:
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4; }
对枚举来说, 如果设置了 option allow_alias = true; 就可以让枚举项的值一样,相当于起了别名。
enum EnumAllowingAlias { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; }
定义引用
Message 可以使用其他 Message作为字段,即嵌套定义,比如下面定义:
message SearchResponse { repeated Result result = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
这里的 repeated 关键字相当于定义了一个对应的数组,数组元素是其后的类型, 数组的大小可以是0到很大, 由于历史原因,数值型的repeated字段后面最好加上[packed=true],这样能达到更好的编码效果。
互相引用
如果 proto 文件定义不在这个文件, 我们可以通过下面方式引入:
import "myproject/other_protos.proto";
对于跨多个文件的引用, 这时候我们会用到 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
public 的定义会一直嵌套带入 import。
内部Message, 嵌套定义
你可以在 message 内部定义 message,如下面代码:
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result result = 1; }
需要使用这个内部 message时,可以这么使用:
message SomeOtherMessage { SearchResponse.Result result = 1; }
由于有这个命名空间层级关系, 你可以这么定义:
message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 int64 ival = 1; bool booly = 2; } } message MiddleBB { // Level 1 message Inner { // Level 2 int32 ival = 1; bool booly = 2; } } }
最里面的两个 message 的字段名称一样,只是字段类型不一样。
参考资料:
Language Guide (proto3)
https://developers.google.com/protocol-buffers/docs/proto3?hl=zh-cn