gRPC之proto語法

本文描述如何使用proto3語法去構造你的數據結構,對官方文檔不徹底譯文,只是摘出本人須要的部分來簡單翻譯官網地址,若是你沒法進入官網連接請自行"跳牆"-_-.java

目錄
  • 1 定義消息類型
    • 1.1 指定字段類型
    • 1.2 分配標量
    • 1.3 指定屬性規則
    • 1.4 添加更多的消息類型
    • 1.5 添加註釋
    • 1.6 保留屬性
  • 2 數據類型
  • 3 默認值
  • 4 枚舉
  • 5 引用其餘的消息類型
    • 5.1 導入其餘proto中定義的消息
  • 6 內嵌類型
  • 8 包
  • 9 服務定義
  • 10 選項

1.定義消息類型

讓咱們先看一個 proto3 的查找請求參數的消息格式的例子,這個請求參數例子模仿分頁查找請求,他有一個請求參數字符串,有一個當前頁的參數還有一個每頁返回數據大小的參數,proto文件內容以下:c++

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
複製代碼
  • 第一行的含義是限定該文件使用的是proto3的語法,若是沒有 syntax = "proto3";編程

  • SearchRequest定義有三個承載消息的屬性,每個被定義在SearchRequest消息體中的字段,都是由數據類型和屬性名稱組成。bash

1.1 指定字段類型

在上面的例子中,全部的屬性都是標量,兩個整型(page_number、result_per_page)和一個字符串(query),你還能夠在指定複合類型,包括枚舉類型或者其餘的消息類型。數據結構

1.2 分配標量

就像所看見的同樣,每個被定義在消息中的字段都會被分配給一個惟一的標量,這些標量用於標識你定義在二進制消息格式中的屬性,標量一旦被定義就不容許在使用過程當中再次被改變。標量的值在1~15的這個範圍裏佔一個字節編碼(詳情請參看 谷歌的 Protocol Buffer Encoding )。編程語言

1.3 指定屬性規則

消息屬性規則以下:

ui

  • singular: 一個正確的消息能夠有零個或者多個這樣的消息屬性(可是不要超過一個).
  • repeated: 這個屬性能夠在一個正確的消息格式中重複任意次數(包括零次),
    在proto3中,標量數字類型的重複字段默認使用壓縮編碼

1.4 添加更多的消息類型

在一個proto文件中能夠定義多個消息類型,你能夠在一個文件中定義一些相關的消息類型,上面的例子proto文件中只有一個請求查找的消息類型,如今能夠爲他多添加一個響應的消息類型,具體以下:google

syntax = "proto3";

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

message SearchResponse {
    ....
}
複製代碼

1.5 添加註釋

proto文件中的註釋使用的是c/c++中的單行註釋 // 語法風格。
以下:編碼

message SearchRequest {
  string query = 1;
  int32 page_number = 2;  // 當前頁數
  int32 result_per_page = 3;  // 每頁數據返回的數據量
複製代碼

1.6 保留屬性

爲了不在加載相同的.proto的舊版本,包括數據損壞,隱含的錯誤等,這可能會致使嚴重的問題的方法是指定刪除的字段的字段標籤(和/或名稱,也可能致使JSON序列化的問題)被保留。 若是未來的用戶嘗試使用這些字段標識符,協議緩衝區編譯器將會報錯。


保留字段的使用例子:url

message Foo {
  reserved 2;
  reserved "foo", "bar";
}
複製代碼

上述例子定義保留屬性爲"foo", "bar",定義保留屬性位置爲2,即在2這個位置上不能夠定義屬性,如:string name=2;是不容許的,編譯器在編譯proto文件的時候若是發現,2這個位置上有屬性被定義則會報錯。

2 數據類型



一個信息標量具備以下表格所示的數據類型,下表主要是對.proto文件的值類型和java的值類型的對照表

.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 默認值

當proto消息被解析成具體的語言的時候,若是消息編碼沒包含特定的元素,則消息對象中的屬性會被設置默認值,這些默認值具體以下:

  • string類型,默認值是空字符串,注意不是null
  • bytes類型,默認值是空bytes
  • bool類型,默認值是false
  • 數字類型,默認值是0
  • 枚舉類型,默認值是第一個枚舉值,即0
  • repeated修飾的屬性,默認值是空(在相對應的編程語言中一般是一個空的list).

4 枚舉

proto容許你在定義的消息類型的時候定義枚舉類型,以下例,在消息類型中定義並使用枚舉類型:

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,緣由以下:

  • 必須有一個0做爲值,以致於咱們但是使用0做爲默認值
  • 第一個元素的值取0,用於與第一個元素枚舉值做爲默認值的proto2語義兼容


    枚舉類型容許你定義別名,別名的做用是分配不中的標量,使用相同的常量值,使用別名只須要在定義枚舉類型的第一行中添加allow_alias選項,並將值設置爲true便可,若是沒有設置該值就是用別名,在編譯的時候會報錯。


    官網例子以下:
enum EnumAllowingAlias {
  option allow_alias = true;
  UNKNOWN = 0;
  STARTED = 1;
  RUNNING = 1;
}
enum EnumNotAllowingAlias {
  UNKNOWN = 0;
  STARTED = 1;
  //若是解除這個註釋編譯器在編譯該proto文的時候會報錯
  // RUNNING = 1; 
}
複製代碼

proto支持的枚舉值的範圍是32位的整形,即Java 中的int類型,其餘請參看官網。

5 引用其餘的消息類型

你能夠在定義消息類型的時候飲用其餘已經定義好的消息類型做爲新消息類型的屬性,官網例子以下:

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}
複製代碼

在上面的消息例子中,SearchResponse這個響應消息類型的屬性results,返回的是一個Result類型的消息列表。

5.1 導入其餘proto中定義的消息

在上面的例子中,Result和SearchResponse消息類型被定義在同一個.proto文件中,若是把他們分紅兩個文件定義,應該如何引用呢?


proto中爲咱們提供了import 關鍵字用於引入不一樣.proto文件中的消息類型,你能夠在你的.proto文件的頂部加入以下語句由於其餘.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同級目錄的test下
syntax = "proto3";
package test2;

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}
複製代碼

若是兩個.proto文件在同一個目錄下直接這樣import "result.proto";倒入便可。

6 內嵌類型

咱們還能夠在消息類型中定義消息,例子以下:

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

在上面的例子中在SearchResponse消息體中定義了一個Result消息並使用。


若是想在其餘的消息體引用Result這個消息,能夠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能夠是任何整數或字符串類型(除浮點類型和字節以外的任何標量類型,枚舉類型也是不合法的key類型),value_type能夠是任何類型的數據。


map更具體的使用方式參看API

8 包

能夠爲proto文件指定包名,防止消息命名衝突。


例子以下:

package foo.bar;
message Open { ... }
複製代碼

當你在爲消息類型定義屬性的時候,你能夠經過命名.類型的形式來使用已經定義好的消息類型,以下:

Message Foo {
  ...
  foo.bar.Open open = 1;
  ...
}
複製代碼

9 服務定義

若是你想在RPC中使用已經定義好的消息類型,你能夠在.proto文件中定一個消息服務接口,protocol buffer編譯器會生成對應語言的接口代碼。

  • 接口定義例子:
service SearchService {
    // 方法名 方法參數 返回值
    rpc Search(SearchRequest) returns (SearchResponse); 
}
複製代碼

10 選項

下面只列出java的.proto文件經常使用的一下選賢,其餘選項前參看官網文檔

  • java_package(文件選項):指定生成的java類所在的包, 若是在.proto文件中沒有提供明確的java_package選項,那麼默認狀況下,將使用proto包。若是沒有生成java代碼該選項默認是不生效的。
    option java_package = "org.example.foo";

  • java_multiple_files(文件選項):指定在proto文件中定義的全部消息、枚舉和服務在生成java類的時候都會生成對應的java類文件,而不是之內部類的形式出現。
    option java_multiple_files = true;

  • java_outer_classname(文件選項):指定生成的java類文件名稱,若是不指定則會默認使用.proto文件的文件名稱,若是沒有生成java類文件,則該選項不會生效 <span id="1">Hello World</span>。
    option java_outer_classname = "HelloWorld";

相關文章
相關標籤/搜索