关于java:protocol-buffer没那么难不信你看这篇

简介

上一篇文章咱们对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
fixed64 8个字节的整数 long
sfixed32 4个字节的带符号整数 int
sfixed64 8个字节的带符号整数 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/

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

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理