轉自: http://www.javashuo.com/article/p-zdwnwglv-hw.htmlphp
英文原文:
Language Guide (proto3)
中文出處:
Protobuf語言指南
[譯]Protobuf 語法指南
中文出處是proto2的譯文,proto3的英文出現後在原來基礎上增改了,水平有限,還請指正html
這個指南描述瞭如何使用Protocol buffer 語言去描述你的protocol buffer 數據, 包括 .proto文件符號和如何從.proto文件生成類。包含了proto2版本的protocol buffer語言:對於老版本的proto3 符號,請見Proto2 Language Guide(以及中文譯本,抄了不少這裏的感謝下老版本的翻譯者)java
本文是一個參考指南——若是要查看如何使用本文中描述的多個特性的按部就班的例子,請在教程中查找須要的語言的教程。python
先來看一個很是簡單的例子。假設你想定義一個「搜索請求」的消息格式,每個請求含有一個查詢字符串、你感興趣的查詢結果所在的頁數,以及每一頁多少條查詢結果。能夠採用以下的方式來定義消息類型的.proto文件了:git
syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
在上面的例子中,全部字段都是標量類型:兩個整型(page_number和result_per_page),一個string類型(query)。固然,你也能夠爲字段指定其餘的合成類型,包括枚舉(enumerations)或其餘消息類型。github
正如你所見,在消息定義中,每一個字段都有惟一的一個數字標識符。這些標識符是用來在消息的二進制格式中識別各個字段的,一旦開始使用就不可以再改變。注:[1,15]以內的標識號在編碼的時候會佔用一個字節。[16,2047]以內的標識號則佔用2個字節。因此應該爲那些頻繁出現的消息元素保留 [1,15]以內的標識號。切記:要爲未來有可能添加的、頻繁出現的標識號預留一些標識號。golang
最小的標識號能夠從1開始,最大到2^29 - 1, or 536,870,911。不可使用其中的[19000-19999]( (從FieldDescriptor::kFirstReservedNumber 到 FieldDescriptor::kLastReservedNumber))的標識號, Protobuf協議實現中對這些進行了預留。若是非要在.proto文件中使用這些預留標識號,編譯時就會報警。一樣你也不能使用早期保留的標識號。objective-c
所指定的消息字段修飾符必須是以下之一:json
repeated:在一個格式良好的消息中,這種字段能夠重複任意屢次(包括0次)。重複的值的順序會被保留。api
在proto3中,repeated的標量域默認狀況蝦使用packed。
你能夠了解更多的pakced屬性在Protocol Buffer 編碼
在一個.proto文件中能夠定義多個消息類型。在定義多個相關的消息的時候,這一點特別有用——例如,若是想定義與SearchResponse消息類型對應的回覆消息格式的話,你能夠將它添加到相同的.proto文件中,如:
message SearchRequest {
string query = 1; int32 page_number = 2; int32 result_per_page = 3; } message SearchResponse { ... }
向.proto文件添加註釋,可使用C/C++/java風格的雙斜槓(//) 語法格式,如:
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. }
若是你經過刪除或者註釋全部域,之後的用戶能夠重用標識號當你從新更新類型的時候。若是你使用舊版本加載相同的.proto文件這會致使嚴重的問題,包括數據損壞、隱私錯誤等等。如今有一種確保不會發生這種狀況的方法就是指定保留標識符(and/or names, which can also cause issues for JSON serialization不明白什麼意思),protocol buffer的編譯器會警告將來嘗試使用這些域標識符的用戶。
message Foo {
reserved 2, 15, 9 to 11; reserved "foo", "bar"; }
注:不要在同一行reserved聲明中同時聲明域名字和標識號
當用protocol buffer編譯器來運行.proto文件時,編譯器將生成所選擇語言的代碼,這些代碼能夠操做在.proto文件中定義的消息類型,包括獲取、設置字段值,將消息序列化到一個輸出流中,以及從一個輸入流中解析消息。
你能夠從以下的文檔連接中獲取每種語言更多API(proto3版本的內容很快就公佈)。API Reference
一個標量消息字段能夠含有一個以下的類型——該表格展現了定義於.proto文件中的類型,以及與之對應的、在自動生成的訪問類中定義的類型:
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type | Ruby Type | C# Type | PHP Type |
---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | |
float | float | float | float | float32 | Float | float | float | |
int32 | 使用變長編碼,對於負值的效率很低,若是你的域有可能有負值,請使用sint64替代 | int32 | int | int | int32 | Fixnum 或者 Bignum(根據須要) | int | integer |
uint32 | 使用變長編碼 | uint32 | int | int/long | uint32 | Fixnum 或者 Bignum(根據須要) | uint | integer |
uint64 | 使用變長編碼 | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string |
sint32 | 使用變長編碼,這些編碼在負值時比int32高效的多 | int32 | int | int | int32 | Fixnum 或者 Bignum(根據須要) | int | integer |
sint64 | 使用變長編碼,有符號的整型值。編碼時比一般的int64高效。 | int64 | long | int/long | int64 | Bignum | long | integer/string |
fixed32 | 老是4個字節,若是數值老是比老是比228大的話,這個類型會比uint32高效。 | uint32 | int | int | uint32 | Fixnum 或者 Bignum(根據須要) | uint | integer |
fixed64 | 老是8個字節,若是數值老是比老是比256大的話,這個類型會比uint64高效。 | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string |
sfixed32 | 老是4個字節 | int32 | int | int | int32 | Fixnum 或者 Bignum(根據須要) | int | integer |
sfixed64 | 老是8個字節 | int64 | long | int/long | int64 | Bignum | long | integer/string |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | |
string | 一個字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本。 | string | String | str/unicode | string | String (UTF-8) | string | string |
bytes | 可能包含任意順序的字節數據。 | string | ByteString | str | []byte | String (ASCII-8BIT) | ByteString | string |
你能夠在文章Protocol Buffer 編碼中,找到更多「序列化消息時各類類型如何編碼」的信息。
當一個消息被解析的時候,若是被編碼的信息不包含一個特定的singular元素,被解析的對象鎖對應的域被設置位一個默認值,對於不一樣類型指定以下:
對於消息類型(message),域沒有被設置,確切的消息是根據語言肯定的,詳見generated code guide
對於可重複域的默認值是空(一般狀況下是對應語言中空列表)。
注:對於標量消息域,一旦消息被解析,就沒法判斷域釋放被設置爲默認值(例如,例如boolean值是否被設置爲false)仍是根本沒有被設置。你應該在定義你的消息類型時很是注意。例如,好比你不該該定義boolean的默認值false做爲任何行爲的觸發方式。也應該注意若是一個標量消息域被設置爲標誌位,這個值不該該被序列化傳輸。
查看generated code guide選擇你的語言的默認值的工做細節。
當須要定義一個消息類型的時候,可能想爲一個字段指定某「預約義值序列」中的一個值。例如,假設要爲每個SearchRequest消息添加一個 corpus字段,而corpus的值多是UNIVERSAL,WEB,IMAGES,LOCAL,NEWS,PRODUCTS或VIDEO中的一個。 其實能夠很容易地實現這一點:經過向消息定義中添加一個枚舉(enum)而且爲每一個可能的值定義一個常量就能夠了。
在下面的例子中,在消息格式中添加了一個叫作Corpus的枚舉類型——它含有全部可能的值 ——以及一個類型爲Corpus的字段:
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,這是由於:
這個零值必須爲第一個元素,爲了兼容proto2語義,枚舉類的第一個值老是默認值。
你能夠經過將不一樣的枚舉常量指定位相同的值。若是這樣作你須要將allow_alias設定位true,不然編譯器會在別名的地方產生一個錯誤信息。
enum EnumAllowingAlias { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; } enum EnumNotAllowingAlias { UNKNOWN = 0; STARTED = 1; // RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside. }
枚舉常量必須在32位整型值的範圍內。由於enum值是使用可變編碼方式的,對負數不夠高效,所以不推薦在enum中使用負數。如上例所示,能夠在 一個消息定義的內部或外部定義枚舉——這些枚舉能夠在.proto文件中的任何消息定義裏重用。固然也能夠在一個消息中聲明一個枚舉類型,而在另外一個不一樣 的消息中使用它——採用MessageType.EnumType的語法格式。
當對一個使用了枚舉的.proto文件運行protocol buffer編譯器的時候,生成的代碼中將有一個對應的enum(對Java或C++來講),或者一個特殊的EnumDescriptor類(對 Python來講),它被用來在運行時生成的類中建立一系列的整型值符號常量(symbolic constants)。
在反序列化的過程當中,沒法識別的枚舉值會被保存在消息中,雖然這種表示方式須要依據所使用語言而定。在那些支持開放枚舉類型超出指定範圍以外的語言中(例如C++和Go),爲識別的值會被表示成所支持的整型。在使用封閉枚舉類型的語言中(Java),使用枚舉中的一個類型來表示未識別的值,而且可使用所支持整型來訪問。在其餘狀況下,若是解析的消息被序列號,未識別的值將保持原樣。
關於如何在你的應用程序的消息中使用枚舉的更多信息,請查看所選擇的語言generated code guide
你能夠將其餘消息類型用做字段類型。例如,假設在每個SearchResponse消息中包含Result消息,此時能夠在相同的.proto文件中定義一個Result消息類型,而後在SearchResponse消息中指定一個Result類型的字段,如:
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
在上面的例子中,Result消息類型與SearchResponse是定義在同一文件中的。若是想要使用的消息類型已經在其餘.proto文件中已經定義過了呢?
你能夠經過導入(importing)其餘.proto文件中的定義來使用它們。要導入其餘.proto文件的定義,你須要在你的文件中添加一個導入聲明,如:
import "myproject/other_protos.proto";
默認狀況下你只能使用直接導入的.proto文件中的定義. 然而, 有時候你須要移動一個.proto文件到一個新的位置, 能夠不直接移動.proto文件, 只需放入一個僞 .proto 文件在老的位置, 而後使用import public轉向新的位置。import public 依賴性會經過任意導入包含import public聲明的proto文件傳遞。例如:
// 這是新的proto // All definitions are moved here
// 這是久的proto // 這是全部客戶端正在導入的包 import public "new.proto"; import "other.proto";
// 客戶端proto import "old.proto"; // 如今你可使用新久兩種包的proto定義了。
經過在編譯器命令行參數中使用-I/--proto_path
protocal 編譯器會在指定目錄搜索要導入的文件。若是沒有給出標誌,編譯器會搜索編譯命令被調用的目錄。一般你只要指定proto_path標誌爲你的工程根目錄就好。而且指定好導入的正確名稱就好。
在你的proto3消息中導入proto2的消息類型也是能夠的,反之亦然,而後proto2枚舉不能夠直接在proto3的標識符中使用(若是僅僅在proto2消息中使用是能夠的)。
你能夠在其餘消息類型中定義、使用消息類型,在下面的例子中,Result消息就定義在SearchResponse消息內,如:
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }
若是你想在它的父消息類型的外部重用這個消息類型,你須要以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; } } }
若是一個已有的消息格式已沒法知足新的需求——如,要在消息中添加一個額外的字段——可是同時舊版本寫的代碼仍然可用。不用擔憂!更新消息而不破壞已有代碼是很是簡單的。在更新時只要記住如下的規則便可。
Any類型消息容許你在沒有指定他們的.proto定義的狀況下使用消息做爲一個嵌套類型。一個Any類型包括一個能夠被序列化bytes類型的任意消息,以及一個URL做爲一個全局標識符和解析消息類型。爲了使用Any類型,你須要導入import google/protobuf/any.proto
import "google/protobuf/any.proto"; message ErrorStatus { string message = 1; repeated google.protobuf.Any details = 2; }
對於給定的消息類型的默認類型URL是type.googleapis.com/packagename.messagename
。
不一樣語言的實現會支持動態庫以線程安全的方式去幫助封裝或者解封裝Any值。例如在java中,Any類型會有特殊的pack()
和unpack()
訪問器,在C++中會有PackFrom()
和UnpackTo()
方法。
// Storing an arbitrary message type in Any. NetworkErrorDetails details = ...; ErrorStatus status; status.add_details()->PackFrom(details); // Reading an arbitrary message from Any. ErrorStatus status = ...; for (const Any& detail : status.details()) { if (detail.Is<NetworkErrorDetails>()) { NetworkErrorDetails network_error; detail.UnpackTo(&network_error); ... processing network_error ... } }
目前,用於Any類型的動態庫仍在開發之中
若是你的消息中有不少可選字段, 而且同時至多一個字段會被設置, 你能夠增強這個行爲,使用oneof特性節省內存.
Oneof字段就像可選字段, 除了它們會共享內存, 至多一個字段會被設置。 設置其中一個字段會清除其它字段。 你可使用case()
或者WhichOneof()
方法檢查哪一個oneof字段被設置, 看你使用什麼語言了.
爲了在.proto定義Oneof字段, 你須要在名字前面加上oneof關鍵字, 好比下面例子的test_oneof:
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }
而後你能夠增長oneof字段到 oneof 定義中. 你能夠增長任意類型的字段, 可是不能使用repeated 關鍵字.
在產生的代碼中, oneof字段擁有一樣的 getters 和setters, 就像正常的可選字段同樣. 也有一個特殊的方法來檢查到底那個字段被設置. 你能夠在相應的語言API指南中找到oneof API介紹.
SampleMessage message; message.set_name("name"); CHECK(message.has_name()); message.mutable_sub_message(); // Will clear name field. CHECK(!message.has_name());
repeated
.sub_message
已經經過set_name()
刪除了SampleMessage message;
SubMessage* sub_message = message.mutable_sub_message(); message.set_name("name"); // Will delete sub_message sub_message->set_... // Crashes here
Swap()
兩個oneof消息,每一個消息,兩個消息將擁有對方的值,例如在下面的例子中,msg1
會擁有sub_message
而且msg2
會有name
。SampleMessage msg1; msg1.set_name("name"); SampleMessage msg2; msg2.mutable_sub_message(); msg1.swap(&msg2); CHECK(msg1.has_sub_message()); CHECK(msg2.has_name());
當增長或者刪除oneof字段時必定要當心. 若是檢查oneof的值返回None/NOT_SET
, 它意味着oneof字段沒有被賦值或者在一個不一樣的版本中賦值了。 你不會知道是哪一種狀況,由於沒有辦法判斷若是未識別的字段是一個oneof字段。
Tage 重用問題:
若是你但願建立一個關聯映射,protocol buffer提供了一種快捷的語法:
map<key_type, value_type> map_field = N;
其中key_type
能夠是任意Integer或者string類型(因此,除了floating和bytes的任意標量類型都是能夠的)value_type
能夠是任意類型。
例如,若是你但願建立一個project的映射,每一個Projecct
使用一個string做爲key,你能夠像下面這樣定義:
map<string, Project> projects = 3;
生成map的API如今對於全部proto3支持的語言均可用了,你能夠從API指南找到更多信息。
map語法序列化後等同於以下內容,所以即便是不支持map語法的protocol buffer實現也是能夠處理你的數據的:
message MapFieldEntry {
key_type key = 1; value_type value = 2; } repeated MapFieldEntry map_field = N;
固然能夠爲.proto文件新增一個可選的package聲明符,用來防止不一樣的消息類型有命名衝突。如:
package foo.bar;
message Open { ... }
在其餘的消息格式定義中可使用包名+消息名的方式來定義域的類型,如:
message Foo {
... required foo.bar.Open open = 1; ... }
包的聲明符會根據使用語言的不一樣影響生成的代碼。
Open
會被封裝在 foo::bar
空間中; - 對於Java,包聲明符會變爲java的一個包,除非在.proto文件中提供了一個明確有java_package
;option go_package
在你的.proto文件中。Open
會在Foo::Bar
名稱空間中。option java_package
。PascalCase
後做爲名稱空間,除非你在你的文件中顯式的提供一個option csharp_namespace
,例如,Open
會在Foo.Bar
名稱空間中Protocol buffer語言中類型名稱的解析與C++是一致的:首先從最內部開始查找,依次向外進行,每一個包會被看做是其父類包的內部類。固然對於 (foo.bar.Baz
)這樣以「.」分隔的意味着是從最外圍開始的。
ProtocolBuffer編譯器會解析.proto文件中定義的全部類型名。 對於不一樣語言的代碼生成器會知道如何來指向每一個具體的類型,即便它們使用了不一樣的規則。
若是想要將消息類型用在RPC(遠程方法調用)系統中,能夠在.proto文件中定義一個RPC服務接口,protocol buffer編譯器將會根據所選擇的不一樣語言生成服務接口代碼及存根。如,想要定義一個RPC服務並具備一個方法,該方法可以接收 SearchRequest並返回一個SearchResponse,此時能夠在.proto文件中進行以下定義:
service SearchService { rpc Search (SearchRequest) returns (SearchResponse); }
最直觀的使用protocol buffer的RPC系統是gRPC一個由谷歌開發的語言和平臺中的開源的PRC系統,gRPC在使用protocl buffer時很是有效,若是使用特殊的protocol buffer插件能夠直接爲您從.proto文件中產生相關的RPC代碼。
若是你不想使用gRPC,也可使用protocol buffer用於本身的RPC實現,你能夠從proto2語言指南中找到更多信息
還有一些第三方開發的PRC實現使用Protocol Buffer。參考第三方插件wiki查看這些實現的列表。
Proto3 支持JSON的編碼規範,使他更容易在不一樣系統之間共享數據,在下表中逐個描述類型。
若是JSON編碼的數據丟失或者其自己就是null
,這個數據會在解析成protocol buffer的時候被表示成默認值。若是一個字段在protocol buffer中表示爲默認值,體會在轉化成JSON的時候編碼的時候忽略掉以節省空間。具體實現能夠提供在JSON編碼中可選的默認值。
proto3 | JSON | JSON示例 | 注意 |
---|---|---|---|
message | object | {「fBar」: v, 「g」: null, …} | 產生JSON對象,消息字段名能夠被映射成lowerCamelCase形式,而且成爲JSON對象鍵,null被接受併成爲對應字段的默認值 |
enum | string | 「FOO_BAR」 | 枚舉值的名字在proto文件中被指定 |
map | object | {「k」: v, …} | 全部的鍵都被轉換成string |
repeated V | array | [v, …] | null被視爲空列表 |
bool | true, false | true, false | |
string | string | 「Hello World!」 | |
bytes | base64 string | 「YWJjMTIzIT8kKiYoKSctPUB+」 | |
int32, fixed32, uint32 | number | 1, -10, 0 | JSON值會是一個十進制數,數值型或者string類型都會接受 |
int64, fixed64, uint64 | string | 「1」, 「-10」 | JSON值會是一個十進制數,數值型或者string類型都會接受 |
float, double | number | 1.1, -10.0, 0, 「NaN」, 「Infinity」 | JSON值會是一個數字或者一個指定的字符串如」NaN」,」infinity」或者」-Infinity」,數值型或者字符串都是可接受的,指數符號也能夠接受 |
Any | object | {「@type」: 「url」, 「f」: v, … } | 若是一個Any保留一個特上述的JSON映射,則它會轉換成一個以下形式:{"@type": xxx, "value": yyy} 不然,該值會被轉換成一個JSON對象,@type 字段會被插入所指定的肯定的值 |
Timestamp | string | 「1972-01-01T10:00:20.021Z」 | 使用RFC 339,其中生成的輸出將始終是Z-歸一化啊的,而且使用0,3,6或者9位小數 |
Duration | string | 「1.000340012s」, 「1s」 | 生成的輸出老是0,3,6或者9位小數,具體依賴於所須要的精度,接受全部能夠轉換爲納秒級的精度 |
Struct | object | { … } | 任意的JSON對象,見struct.proto |
Wrapper types | various types | 2, 「2」, 「foo」, true, 「true」, null, 0, … | 包裝器在JSON中的表示方式相似於基本類型,可是容許nulll,而且在轉換的過程當中保留null |
FieldMask | string | 「f.fooBar,h」 | 見fieldmask.proto |
ListValue | array | [foo, bar, …] | |
Value | value | 任意JSON值 | |
NullValue | null | JSON null |
在定義.proto文件時可以標註一系列的options。Options並不改變整個文件聲明的含義,但卻可以影響特定環境下處理方式。完整的可用選項能夠在google/protobuf/descriptor.proto找到。
一些選項是文件級別的,意味着它能夠做用於最外範圍,不包含在任何消息內部、enum或服務定義中。一些選項是消息級別的,意味着它能夠用在消息定義的內部。固然有些選項能夠做用在域、enum類型、enum值、服務類型及服務方法中。到目前爲止,並無一種有效的選項能做用於全部的類型。
以下就是一些經常使用的選擇:
java_package
(文件選項) :這個選項代表生成java類所在的包。若是在.proto文件中沒有明確的聲明java_package,就採用默認的包名。固然了,默認方式產生的 java包名並非最好的方式,按照應用名稱倒序方式進行排序的。若是不須要產生java代碼,則該選項將不起任何做用。如:option java_package = "com.example.foo";
java_outer_classname
(文件選項): 該選項代表想要生成Java類的名稱。若是在.proto文件中沒有明確的java_outer_classname定義,生成的class名稱將會根據.proto文件的名稱採用駝峯式的命名方式進行生成。如(foo_bar.proto生成的java類名爲FooBar.java),若是不生成java代碼,則該選項不起任何做用。如:option java_outer_classname = "Ponycopter";
optimize_for
(文件選項): 能夠被設置爲 SPEED, CODE_SIZE,或者LITE_RUNTIME。這些值將經過以下的方式影響C++及java代碼的生成: SPEED (default)
: protocol buffer編譯器將經過在消息類型上執行序列化、語法分析及其餘通用的操做。這種代碼是最優的。CODE_SIZE
: protocol buffer編譯器將會產生最少許的類,經過共享或基於反射的代碼來實現序列化、語法分析及各類其它操做。採用該方式產生的代碼將比SPEED要少得多, 可是操做要相對慢些。固然實現的類及其對外的API與SPEED模式都是同樣的。這種方式常常用在一些包含大量的.proto文件並且並不盲目追求速度的 應用中。LITE_RUNTIME
: protocol buffer編譯器依賴於運行時核心類庫來生成代碼(即採用libprotobuf-lite 替代libprotobuf)。這種核心類庫因爲忽略了一 些描述符及反射,要比全類庫小得多。這種模式常常在移動手機平臺應用多一些。編譯器採用該模式產生的方法實現與SPEED模式不相上下,產生的類經過實現 MessageLite接口,但它僅僅是Messager接口的一個子集。option optimize_for = CODE_SIZE;
cc_enable_arenas
(文件選項):對於C++產生的代碼啓用arena allocationobjc_class_prefix
(文件選項):設置Objective-C類的前綴,添加到全部Objective-C今後.proto文件產生的類和枚舉類型。沒有默認值,所使用的前綴應該是蘋果推薦的3-5個大寫字符,注意2個字節的前綴是蘋果所保留的。deprecated
(字段選項):若是設置爲true
則表示該字段已經被廢棄,而且不該該在新的代碼中使用。在大多數語言中沒有實際的意義。在java中,這回變成@Deprecated
註釋,在將來,其餘語言的代碼生成器也許會在字標識符中產生廢棄註釋,廢棄註釋會在編譯器嘗試使用該字段時發出警告。若是字段沒有被使用你也不但願有新用戶使用它,嘗試使用保留語句替換字段聲明。int32 old_field = 6 [deprecated=true];
ProtocolBuffers容許自定義並使用選項。該功能應該屬於一個高級特性,對於大部分人是用不到的。若是你的確但願建立本身的選項,請參看 Proto2 Language Guide。注意建立自定義選項使用了拓展,拓展只在proto3中可用。
能夠經過定義好的.proto文件來生成Java,Python,C++, Ruby, JavaNano, Objective-C,或者C# 代碼,須要基於.proto文件運行protocol buffer編譯器protoc。若是你沒有安裝編譯器,下載安裝包並遵守README安裝。對於Go,你還須要安裝一個特殊的代碼生成器插件。你能夠經過GitHub上的protobuf庫找到安裝過程
經過以下方式調用protocol編譯器:
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
IMPORT_PATH
聲明瞭一個.proto文件所在的解析import具體目錄。若是忽略該值,則使用當前目錄。若是有多個目錄則能夠屢次調用--proto_path
,它們將會順序的被訪問並執行導入。-I=IMPORT_PATH
是--proto_path
的簡化形式。--cpp_out
在目標目錄DST_DIR中產生C++代碼,能夠在C++代碼生成參考中查看更多。--java_out
在目標目錄DST_DIR中產生Java代碼,能夠在 Java代碼生成參考中查看更多。--python_out
在目標目錄 DST_DIR 中產生Python代碼,能夠在Python代碼生成參考中查看更多。--go_out
在目標目錄 DST_DIR 中產生Go代碼,能夠在GO代碼生成參考中查看更多。--ruby_out
在目標目錄 DST_DIR 中產生Go代碼,參考正在製做中。--javanano_out
在目標目錄DST_DIR中生成JavaNano,JavaNano代碼生成器有一系列的選項用於定製自定義生成器的輸出:你能夠經過生成器的README查找更多信息,JavaNano參考正在製做中。--objc_out
在目標目錄DST_DIR中產生Object代碼,能夠在Objective-C代碼生成參考中查看更多。--csharp_out
在目標目錄DST_DIR中產生Object代碼,能夠在C#代碼生成參考中查看更多。--php_out
在目標目錄DST_DIR中產生Object代碼,能夠在PHP代碼生成參考中查看更多。做爲一個方便的拓展,若是DST_DIR以.zip或者.jar結尾,編譯器會將輸出寫到一個ZIP格式文件或者符合JAR標準的.jar文件中。注意若是輸出已經存在則會被覆蓋,編譯器尚未智能到能夠追加文件。 - 你必須提議一個或多個.proto文件做爲輸入,多個.proto文件能夠只指定一次。雖然文件路徑是相對於當前目錄的,每一個文件必須位於其IMPORT_PATH下,以便每一個文件能夠肯定其規範的名稱。