简介

上一篇文章咱们对google的protobuf曾经有了一个根本的意识,并且可能应用相应的工具生成对应的代码了。然而对于.proto文件的格局和具体反对的类型还不是很分明。明天本文将会带大家一探到底。

留神,本文介绍的协定是proto3版本的。

定义一个音讯

protobuf中的主体被称为是message,能够将其看做是咱们在程序中定义的类。咱们能够在.proto文件中定义这个message对象,并且为其增加属性,如下所示:

syntax = "proto3";message SearchRequest {  string query = 1;  int32 page_number = 2;  int32 result_per_page = 3;}

上例的第一行指定了.proto文件的协定类型,这里应用的是proto3,也是最新版的协定,如果不指定,默认状况下是proto2。

类型定义

这里咱们为SearchRequest对象,定义了三个属性,其类型别离是String和int32。

String和int32都是简略类型,protobuf反对的简略类型如下:

protobuf类型阐明对应的java类型
double双精度浮点类型double
float浮点类型float
int32整型数字,最好不示意正数int
int64整型数字,最好不示意正数long
uint32无符号整数int
uint64无符号整数long
sint32带符号整数int
sint64带符号整数long
fixed32四个字节的整数int
fixed648个字节的整数long
sfixed324个字节的带符号整数int
sfixed648个字节的带符号整数long
bool布尔类型boolean
string字符串String
bytes字节ByteString

当然protobuf还反对简单的组合类型和枚举类型。

枚举类型在protobuf中用enum来示意,咱们来看一个枚举类型的定义:

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;}

下面咱们定义了一个枚举类型Corpus,枚举类型中定义的枚举值是从0开始的,0也是枚举类型的默认值。

在枚举中,还能够定义具备雷同value的枚举类型,然而这样须要加上allow_alias=true的选项,如下所示:

message MyMessage1 {  enum EnumAllowingAlias {    option allow_alias = true;    UNKNOWN = 0;    STARTED = 1;    RUNNING = 1;  }}message MyMessage2 {  enum EnumNotAllowingAlias {    UNKNOWN = 0;    STARTED = 1;    // RUNNING = 1;  // Uncommenting this line will cause a compile error inside Google and a warning message outside.  }}

在枚举类型中,如果咱们后续对某些枚举类型进行了删除,那么被删除的值可能会被后续的用户应用,这样就会造成潜在的代码隐患,为了解决这个问题,枚举提供了一个reserved的关键词,被这个关键词申明的枚举类型,就不会被后续应用,如下所示:

enum Foo {  reserved 2, 15, 9 to 11, 40 to max;  reserved "FOO", "BAR";}

reserved关键字也能够用在message的字段中,示意后续不要应用到这些字段,如下:

message Foo {  reserved 2, 15, 9 to 11;  reserved "foo", "bar";}

字段的值

咱们能够看到,每个message的字段都调配了一个值,每个字段的值在message中都是惟一的,这些值是用来定位在二进制音讯格局中的字段地位。所以一旦定义之后,不要随便批改。

要留神的是值1-15在二进制中应用的1个字节来示意的,值16-2047须要应用2个字节来示意,所以通常将1-15应用在最常见的字段和可能反复的字段,这样能够节约编码后的空间。

最小的值是1,最大的值是2的29次方-1,或者536,870,911。这两头从19000-19999是保留数字,不能应用。

当音讯被编译之后,各个字段将会被转成为对应的类型,并且各个字段类型将会被赋予不同的初始值。

strings的默认值是空字符串,bytes的默认值是空bytes,bools的默认值是false,数字类型的默认值是0,枚举类型的默认值是枚举的第一个元素。

字段描述符

每个音讯的字段都能够有两种描述符,第一种叫做singular,示意message中能够有0个或者1个这个字段,这是proto3中默认的定义形式。

第二种叫做repeated,示意这个字段在message中是能够反复的,也就是说它代表的是一个汇合。

增加正文

在proto中的正文和C++的格调相似,能够应用: // 或者 / ... / 的格调来正文,如下所示:

/* 这是一个正文. */message SearchRequest {  string query = 1;  int32 page_number = 2;  // 页面的number  int32 result_per_page = 3;  // 每页的后果}

嵌套类型

在一个message中还能够嵌入一个message,如下所示:

message SearchResponse {  message Result {    string url = 1;    string title = 2;    repeated string snippets = 3;  }  repeated Result results = 1;}

在上例中,咱们在SearchResponse定义了一个Result类型,在java中,实际上能够将其看做是嵌套类。

如果心愿在message的定义类之外应用这个外部的message,则能够通过_Parent_._Type_来定义:

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;    }  }}

Map

如果想要在proto中定义map,能够这样写:

map<key_type, value_type> map_field = N;

这里的value_type能够是除map之外的任意类型。留神map不能是repeated。

map中的数据的程序是不定的,咱们不能依赖存入的map程序来判断其取出的程序。

总结

以上就是proto3中定义申明文件该留神的事项了,大家在应用protobuf的时候要多加留神。

本文已收录于 http://www.flydean.com/02-protocolbuf-detail/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!