本文描述如何使用proto3語法去構(gòu)造你的數(shù)據(jù)結(jié)構(gòu)毫目,對(duì)官方文檔不完全譯文诲侮,只是摘出本人需要的部分來簡(jiǎn)單翻譯官網(wǎng)地址沟绪,如果你無法進(jìn)入官網(wǎng)鏈接請(qǐng)自行"跳墻"-_-.
目錄
- 1 定義消息類型
- 1.1 指定字段類型
- 1.2 分配標(biāo)量
- 1.3 指定屬性規(guī)則
- 1.4 添加更多的消息類型
- 1.5 添加注釋
- 1.6 保留屬性
- 2 數(shù)據(jù)類型
- 3 默認(rèn)值
- 4 枚舉
- 5 引用其他的消息類型
- 5.1 導(dǎo)入其他proto中定義的消息
- 6 內(nèi)嵌類型
- 8 包
- 9 服務(wù)定義
- 10 選項(xiàng)
1.定義消息類型
讓我們先看一個(gè) proto3 的查找請(qǐng)求參數(shù)的消息格式的例子空猜,這個(gè)請(qǐng)求參數(shù)例子模仿分頁(yè)查找請(qǐng)求辈毯,他有一個(gè)請(qǐng)求參數(shù)字符串,有一個(gè)當(dāng)前頁(yè)的參數(shù)還有一個(gè)每頁(yè)返回?cái)?shù)據(jù)大小的參數(shù)漓摩,proto文件內(nèi)容如下:
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
第一行的含義是限定該文件使用的是proto3的語法管毙,如果沒有 syntax = "proto3";
SearchRequest定義有三個(gè)承載消息的屬性,每一個(gè)被定義在SearchRequest消息體中的字段啃炸,都是由數(shù)據(jù)類型和屬性名稱組成卓舵。
1.1 指定字段類型
在上面的例子中,所有的屬性都是標(biāo)量裹虫,兩個(gè)整型(page_number融击、result_per_page)和一個(gè)字符串(query),你還可以在指定復(fù)合類型匣屡,包括枚舉類型或者其他的消息類型拇涤。
1.2 分配標(biāo)量
就像所看見的一樣鹅士,每一個(gè)被定義在消息中的字段都會(huì)被分配給一個(gè)唯一的標(biāo)量,這些標(biāo)量用于標(biāo)識(shí)你定義在二進(jìn)制消息格式中的屬性也拜,標(biāo)量一旦被定義就不允許在使用過程中再次被改變。標(biāo)量的值在1~15的這個(gè)范圍里占一個(gè)字節(jié)編碼(詳情請(qǐng)參看 谷歌的 Protocol Buffer Encoding )稀轨。
1.3 指定屬性規(guī)則
消息屬性規(guī)則如下:
singular: 一個(gè)正確的消息可以有零個(gè)或者多個(gè)這樣的消息屬性(但是不要超過一個(gè)).
-
repeated: 這個(gè)屬性可以在一個(gè)正確的消息格式中重復(fù)任意次數(shù)(包括零次),
在proto3中岸军,標(biāo)量數(shù)字類型的重復(fù)字段默認(rèn)使用壓縮編碼
1.4 添加更多的消息類型
在一個(gè)proto文件中可以定義多個(gè)消息類型,你可以在一個(gè)文件中定義一些相關(guān)的消息類型佣谐,上面的例子proto文件中只有一個(gè)請(qǐng)求查找的消息類型方妖,現(xiàn)在可以為他多添加一個(gè)響應(yīng)的消息類型党觅,具體如下:
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
....
}
1.5 添加注釋
proto文件中的注釋使用的是c/c++中的單行注釋 //
語法風(fēng)格。
如下:
message SearchRequest {
string query = 1;
int32 page_number = 2; // 當(dāng)前頁(yè)數(shù)
int32 result_per_page = 3; // 每頁(yè)數(shù)據(jù)返回的數(shù)據(jù)量
1.6 保留屬性
為了避免在加載相同的.proto的舊版本镐牺,包括數(shù)據(jù)損壞魁莉,隱含的錯(cuò)誤等,這可能會(huì)導(dǎo)致嚴(yán)重的問題的方法是指定刪除的字段的字段標(biāo)簽(和/或名稱畦浓,也可能導(dǎo)致JSON序列化的問題)被保留检疫。 如果將來的用戶嘗試使用這些字段標(biāo)識(shí)符电谣,協(xié)議緩沖區(qū)編譯器將會(huì)報(bào)錯(cuò)抹蚀。
保留字段的使用例子:
message Foo {
reserved 2;
reserved "foo", "bar";
}
上述例子定義保留屬性為"foo", "bar"
,定義保留屬性位置為2晒来,即在2這個(gè)位置上不可以定義屬性郑现,如:string name=2;
是不允許的荧降,編譯器在編譯proto文件的時(shí)候如果發(fā)現(xiàn)朵诫,2這個(gè)位置上有屬性被定義則會(huì)報(bào)錯(cuò)薄扁。
2 數(shù)據(jù)類型
一個(gè)信息標(biāo)量具有如下表格所示的數(shù)據(jù)類型,下表主要是對(duì).proto文件的值類型和java的值類型的對(duì)照表
.proto Type | Java Type |
---|---|
double | double |
float | float |
int32 | int |
int64 | long |
uint32 | int |
uint64 | long |
sint32 | int |
sint64 | long |
fixed32 | int |
fixed64 | long |
sfixed32 | int |
sfixed64 | long |
bool | boolean |
string | String |
bytes | ByteString |
3 默認(rèn)值
當(dāng)proto消息被解析成具體的語言的時(shí)候,如果消息編碼沒包含特定的元素日缨,則消息對(duì)象中的屬性會(huì)被設(shè)置默認(rèn)值,這些默認(rèn)值具體如下:
-
string
類型,默認(rèn)值是空字符串,注意不是null -
bytes
類型,默認(rèn)值是空bytes -
bool
類型面哥,默認(rèn)值是false -
數(shù)字
類型,默認(rèn)值是0 -
枚舉
類型,默認(rèn)值是第一個(gè)枚舉值,即0 -
repeated
修飾的屬性幢竹,默認(rèn)值是空(在相對(duì)應(yīng)的編程語言中通常是一個(gè)空的list).
4 枚舉
proto允許你在定義的消息類型的時(shí)候定義枚舉類型恩静,如下例,在消息類型中定義并使用枚舉類型:
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
枚舉類型的第一個(gè)枚舉值是0邑飒,每一個(gè)枚舉值定義都會(huì)與一個(gè)常量映射级乐,而這些常量的第一個(gè)常量值必須為0风科,原因如下:
必須有一個(gè)0作為值,以至于我們可是使用0作為默認(rèn)值
-
第一個(gè)元素的值取0贼穆,用于與第一個(gè)元素枚舉值作為默認(rèn)值的proto2語義兼容
枚舉類型允許你定義別名故痊,別名的作用是分配不中的標(biāo)量,使用相同的常量值慨菱,使用別名只需要在定義枚舉類型的第一行中添加allow_alias
選項(xiàng),并將值設(shè)置為true即可闪彼,如果沒有設(shè)置該值就是用別名协饲,在編譯的時(shí)候會(huì)報(bào)錯(cuò)。
官網(wǎng)例子如下:
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
//如果解除這個(gè)注釋編譯器在編譯該proto文的時(shí)候會(huì)報(bào)錯(cuò)
// RUNNING = 1;
}
proto支持的枚舉值的范圍是32位的整形郊尝,即Java 中的int類型,其他請(qǐng)參看官網(wǎng)战惊。
5 引用其他的消息類型
你可以在定義消息類型的時(shí)候飲用其他已經(jīng)定義好的消息類型作為新消息類型的屬性吞获,官網(wǎng)例子如下:
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
在上面的消息例子中,SearchResponse這個(gè)響應(yīng)消息類型的屬性results刁绒,返回的是一個(gè)Result類型的消息列表烤黍。
5.1 導(dǎo)入其他proto中定義的消息
在上面的例子中,Result和SearchResponse消息類型被定義在同一個(gè).proto文件中嫂丙,如果把他們分成兩個(gè)文件定義规哲,應(yīng)該如何引用呢唉锌?
proto中為我們提供了import
關(guān)鍵字用于引入不同.proto
文件中的消息類型,你可以在你的.proto
文件的頂部加入如下語句因?yàn)槠渌?code>.proto文件的消息類型:
import "myproject/other_protos.proto";
例子:
- 文件名稱
search_response.proto
syntax = "proto3";
import "test/result.proto";
package test1;
message SearchResponse {
//包名.消息名
repeated test2.Result results = 1;
}
- 文件名稱
result.proto,在與search_response.proto同級(jí)目錄的test下
syntax = "proto3";
package test2;
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
如果兩個(gè).proto文件在同一個(gè)目錄下直接這樣import "result.proto";
倒入即可。
6 內(nèi)嵌類型
我們還可以在消息類型中定義消息腥放,例子如下:
message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}
在上面的例子中在SearchResponse消息體中定義了一個(gè)Result消息并使用痘番。
如果想在其他的消息體引用Result這個(gè)消息汞舱,可以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;
}
}
}
7 Map
proto支持map屬性類型的定義泌神,語法如下:
map<key_type,value_type> map_field = N;
key_type可以是任何整數(shù)或字符串類型(除浮點(diǎn)類型和字節(jié)之外的任何標(biāo)量類型,枚舉類型也是不合法的key類型)欢际,value_type可以是任何類型的數(shù)據(jù)。
map更具體的使用方式參看API
8 包
可以為proto
文件指定包名患久,防止消息命名沖突浑槽。
例子如下:
package foo.bar;
message Open { ... }
當(dāng)你在為消息類型定義屬性的時(shí)候,你可以通過命名.類型
的形式來使用已經(jīng)定義好的消息類型篙挽,如下:
Message Foo {
...
foo.bar.Open open = 1;
...
}
9 服務(wù)定義
如果你想在RPC中使用已經(jīng)定義好的消息類型镊靴,你可以在.proto
文件中定一個(gè)消息服務(wù)接口,protocol buffer編譯器會(huì)生成對(duì)應(yīng)語言的接口代碼偏竟。
接口定義例子:
service SearchService {
// 方法名 方法參數(shù) 返回值
rpc Search(SearchRequest) returns (SearchResponse);
}
10 選項(xiàng)
下面只列出java的.proto
文件常用的一下選賢,其他選項(xiàng)前參看官網(wǎng)文檔
java_package
(文件選項(xiàng)):指定生成的java類所在的包州邢, 如果在.proto文件中沒有提供明確的java_package
選項(xiàng)褪子,那么默認(rèn)情況下嫌褪,將使用proto
包。如果沒有生成java代碼該選項(xiàng)默認(rèn)是不生效的笼痛。
option java_package = "org.example.foo";
java_multiple_files
(文件選項(xiàng)):指定在proto文件中定義的所有消息、枚舉和服務(wù)在生成java類的時(shí)候都會(huì)生成對(duì)應(yīng)的java類文件摘刑,而不是以內(nèi)部類的形式出現(xiàn)枷恕。
option java_multiple_files = true;
java_outer_classname
(文件選項(xiàng)):指定生成的java類文件名稱,如果不指定則會(huì)默認(rèn)使用.proto
文件的文件名稱未玻,如果沒有生成java類文件胡控,則該選項(xiàng)不會(huì)生效 <span id="1">Hello World</span>。
option java_outer_classname = "HelloWorld";