message為主要關鍵字,類似于java中的class。
定義簡單message類型
定義簡單message類型
SearchRequest.proto定義了每個查詢請求的消息格式,每個請求都會有查詢關鍵詞query,查詢結果的頁數,每頁的結果數量這三個屬性。于是
?
message?SearchRequest{
????????required?string?query?=?1;
????????optional?int32?page_number?=?2;
????????optional?int32?result_per_page?=3;
????????repeated?int32?samples?=?4?[packed= true ];????
}
????????required?string?query?=?1;
????????optional?int32?page_number?=?2;
????????optional?int32?result_per_page?=3;
????????repeated?int32?samples?=?4?[packed= true ];????
}
message定義了三個field,每個field由名字和類型來組成。
- 指定field類型
在這個例子中,SearchRequest的field都是基本類型,兩個integer(page_number和result_per_page)和一個Stirng(query),也可以指定復雜的類型屬性,包括枚舉和其它類型。
- 分配標簽
每個field都是唯一數字的標記,這是用來標記這個field在message二進制格式中的位置的,一旦使用就不能再修改順序了。
注:標記從1-15只有一個字節編碼,包括自增長屬性(更多的見Protocol Buffer Encoding)
標記從16-2047占用兩個字節。因此盡量頻繁使用1-15,記住為未來的擴展留下一些位置。
最小的tag你可以定義為1,最大2的29次方-1 ?536870922.你同樣不能使用19000-19999(這個位置已經被GPB自己實現),
- 指定field規則
?
message?SearchRequest{
????????required?string?query?=?1 ;
????????optional?int32?page_number?=?2 ;
????????optional?int32?result_per_page?=3 ;
????????repeated?int32?samples?=?4? [ packed=true ] ; ????
}
由于歷史原因,repeated字段如果是基本數字類型的話,不能有效地編碼。現在代碼可以使用特殊選項[packed=true]來得到更有效率的編碼。
????????required?string?query?=?1 ;
????????optional?int32?page_number?=?2 ;
????????optional?int32?result_per_page?=3 ;
????????repeated?int32?samples?=?4? [ packed=true ] ; ????
}
注:
?由于required是永遠的,應該非常慎重地給message某個字段設置為required。如果未來你希望停止寫入或者輸出某個required字段,那就會成為問題;因為舊的reader將以為沒有這個字段無法初始化message,會丟掉這部分信息。一些來自google的工程師們指出使用required弊大于利,盡量使用optional和repeated。
這個觀點并不是通用的。
?
- 更多message類型
多個message類型能被定義在一個簡單的.proto文件中,通常是創建具有關聯關系的message時候這么作。
?
message?SearchRequest{
????????required?string?query?=?1 ;
????????optional?int32?page_number?=?2 ;
????????optional?int32?result_per_page?=3 ;
????????repeated?int32?samples?=?4? [ packed=true ] ; ????
}
????????required?string?query?=?1 ;
????????optional?int32?page_number?=?2 ;
????????optional?int32?result_per_page?=3 ;
????????repeated?int32?samples?=?4? [ packed=true ] ; ????
}
?
- 添加注釋
使用c/C++ style
?
?
message?SearchRequest{
????????required? string ?query?=?1;?? //
????????optional?int32?page_number?=?2;?? // ?which?page?number?do?we?want?
????????optional?int32?result_per_page?=3;? // ?Number?of?results?to?return?per?page?
????????repeated?int32?samples?=?4?[packed= true ];????
}
????????required? string ?query?=?1;?? //
????????optional?int32?page_number?=?2;?? // ?which?page?number?do?we?want?
????????optional?int32?result_per_page?=3;? // ?Number?of?results?to?return?per?page?
????????repeated?int32?samples?=?4?[packed= true ];????
}
?
- .proto文件自動生成代碼
protocol buffer編譯一個proto文件,生成對應語言的代碼。
大概包括各個字段的get和set方法,序列化message到輸出流的方法,從輸入流轉成message的方法。
C++,為每個proto生成一個.h和.cc文件
Java,為每個proto生成一個.java文件
Python,有點不同,生成一個module
?
- 基本屬性 ?
- optional字段和默認值
當含有optional字段的message從流轉換成對象的時候,如果沒有包含optional字段的數據,那么對象的optional字段會設置成默認值。
默認值可以作為message的描述出現。舉個例子:
optional?int32?result_per_page?=?3?
[
default?=?10
]
;
如??
pasting
??果沒有指定默認值的話,string 默認為空串,bool 默認為false,數字類型默認0,枚舉類型,默認為類型定義中的第一個值,
?
- Enumerations
如果字段的屬性值是固定的幾個值,可以使用枚舉
message?SearchRequest?{
??required? string ?query?=?1;
??optional?int32?page_number?=?2;
??optional?int32?result_per_page?=?3?[ default ?=?10];
?? enum ?Corpus?{
????UNIVERSAL?=?0;
????WEB?=?1;
????IMAGES?=?2;
????LOCAL?=?3;
????NEWS?=?4;
????PRODUCTS?=?5;
????VIDEO?=?6;
??}
??optional?Corpus?corpus?=?4?[ default ?=?WEB];
}
??required? string ?query?=?1;
??optional?int32?page_number?=?2;
??optional?int32?result_per_page?=?3?[ default ?=?10];
?? enum ?Corpus?{
????UNIVERSAL?=?0;
????WEB?=?1;
????IMAGES?=?2;
????LOCAL?=?3;
????NEWS?=?4;
????PRODUCTS?=?5;
????VIDEO?=?6;
??}
??optional?Corpus?corpus?=?4?[ default ?=?WEB];
}
?
- 自定義消息類型
可以使用message類型做字段的屬性,看例子:
message?SearchResponse?{
??repeated?Result?result?=?1;
}
message?Result?{
??required? string ?url?=?1;
??optional? string ?title?=?2;
??repeated? string ?snippets?=?3;
}
??repeated?Result?result?=?1;
}
message?Result?{
??required? string ?url?=?1;
??optional? string ?title?=?2;
??repeated? string ?snippets?=?3;
}
?
?
- import 定義
上面的例子SearchResponse 與Result在一個.proto文件中。其實也可以使用另一個.proto文件來定義字段類型。
你可以通過import來定義。
import
?"myproject/other_protos.proto";
?
protocol編譯器查找引入文件是通過編譯器的命令參數 -I/--proto_path
如果沒有指定,就在protoc執行目錄下尋找。
The protocol compiler searches for imported files in a set of directories specified on the protocol compiler command line using the -I/--proto_path flag.?
If no flag was given, it looks in the directory in which the compiler was invoked.?
In general you should set the --proto_path flag to the root of your project and use fully qualified names for all imports.
?
- 內部類
你可以定義和使用內部message類。
message?SearchResponse?{
??message?Result?{
????required?string?url?=?1;
????optional?string?title?=?2;
????repeated?string?snippets?=?3;
??}
??repeated?Result?result?=?1;
}
??message?Result?{
????required?string?url?=?1;
????optional?string?title?=?2;
????repeated?string?snippets?=?3;
??}
??repeated?Result?result?=?1;
}
?
如果要引用內部類,則通過parent.type方式來調用
message?SomeOtherMessage?{
??optional?SearchResponse.Result?result?=?1;
}
??optional?SearchResponse.Result?result?=?1;
}
?
還可以很深、很深的內部類
message?Outer?{??????????????????
//
?Level?0
??message?MiddleAA?{?? // ?Level?1
????message?Inner?{??? // ?Level?2
??????required?int64?ival?=?1;
??????optional?bool??booly?=?2;
????}
??}
??message?MiddleBB?{?? // ?Level?1
????message?Inner?{??? // ?Level?2
??????required?int32?ival?=?1;
??????optional?bool??booly?=?2;
????}
??}
}
??message?MiddleAA?{?? // ?Level?1
????message?Inner?{??? // ?Level?2
??????required?int64?ival?=?1;
??????optional?bool??booly?=?2;
????}
??}
??message?MiddleBB?{?? // ?Level?1
????message?Inner?{??? // ?Level?2
??????required?int32?ival?=?1;
??????optional?bool??booly?=?2;
????}
??}
}
?
- Groups?
message?SearchResponse?{
??repeated?group?Result?=?1?{
????required?string?url?=?2;
????optional?string?title?=?3;
????repeated?string?snippets?=?4;
??}
}
??repeated?group?Result?=?1?{
????required?string?url?=?2;
????optional?string?title?=?3;
????repeated?string?snippets?=?4;
??}
}
?
Extentions
extensions 聲明一個消息中的一定范圍的field的順序數字用于進行擴展。其它人可以在自己的.proto文件中重新定義這些消息field,而不需要去修改原始的.proto文件
message?Foo?{
?? // ?
??extensions?100?to?199;
}
?? // ?

??extensions?100?to?199;
}
這些說明100-199的field是保留的。其它用戶可以用這些field在他們自己的.proto文件中添加新的fields給Foo。舉例:
extend?Foo?{
??optional?int32?bar?=?126;
}
??optional?int32?bar?=?126;
}
說明 Foo有一個optional的int32類型的名稱為bar的field ?
當Foo的message編碼后,數據格式就跟用戶在Foo中定義一個新的field完全一樣。但是你在程序中訪問extension field的方式與訪問正常的屬性略微有點不同。生成的extensions的訪問代碼是不同的。舉例:c++中如何set屬性bar的值:
Foo?foo;
foo.SetExtension(bar,15);
foo.SetExtension(bar,15);
同樣,Foo 定義了模板訪問器 ?HasExtendsion(),ClearExtension(),GetExtension(),MutableExtension(),AddExtension().
所有 訪問 ? ? ??
注: ?extensions能使用任何field類型,包括自定義消息類型。
注: ?extensions能使用任何field類型,包括自定義消息類型。
- 內嵌的extensions
能聲明extensions在另一個message中
message?Baz?{
??extend?Foo?{
????optional?int32?bar?=?126 ;
??}
??
}
??extend?Foo?{
????optional?int32?bar?=?126 ;
??}
??

}
在這個例子中, the C++ 代碼訪問訪問這個屬性:
Foo?foo;
foo.SetExtension(Baz::bar,?15);
foo.SetExtension(Baz::bar,?15);
?
換句話說,這么做唯一影響是bar定義在了Baz的范圍之內。
注意:
容易混淆的地方 聲明一個消息內部的繼承類并不意味著外部類和extended類有任何關系。
特別 以上的例子并不意味著Baz是任何Foo的子類。這些只是意味著符號bar是聲明在Baz的范圍之內的,
它看起來更像是個靜態成員。
一個通用的模式是在extensions的field范圍內來定義extensions,舉例說明,這里有一個Foo的extension作為Baz的一部分的屬性類型是Baz
message?Baz?{
??extend?Foo?{
????optional?Baz?foo_ext?=?127 ;
??}
??
}
??extend?Foo?{
????optional?Baz?foo_ext?=?127 ;
??}
??

}
沒有必要非得在message內部定義一個extension的類型。你也可以這么做:
message?Baz?{
??
}
//?This?can?even?be?in?a?different?file.
extend?Foo?{
??optional?Baz?foo_baz_ext?=?127 ;
}
??

}
//?This?can?even?be?in?a?different?file.
extend?Foo?{
??optional?Baz?foo_baz_ext?=?127 ;
}
?
事實上,上面的這個語法更加有效地避免混淆。正如上文所述,內部的那種語法語法對于不是熟悉extensions的人來說,經常會錯認為子類。
?
- 選擇Extension 順序數字
非常重要的一點是雙方不能使用同樣數字添加一樣的message類型,這樣extension會被解釋為錯誤類型。
可能需要有一個關于field的數字順序的約定來保證你的project不會發生這樣的重復的問題。
如果你的field數字比較大的話,可以使用max來指定你的textension范圍上升到最大的范圍
message?Foo?{
??extensions?1000?to?max ;
}
max?is?229?-?1,?or?536,870,911.
??extensions?1000?to?max ;
}
max?is?229?-?1,?or?536,870,911.
19000-19999是protocol buffers的使用的字段,所以這個范圍內的數字需要區別開來。
?
Packages
可以給一個.protol文件增加一個optional的package描述,來保證message盡量不會出現名字相同的重名。
package?foo.bar
;
message?Open?{?
?
}
message?Open?{?

}
也可以在指定field類型的時候使用
?
message?Foo?{
??
??required?foo.bar.Open?open?=?1 ;
??
}
??

??required?foo.bar.Open?open?=?1 ;
??

}
?
package會根據選擇的語言來生成不同的代碼:
C++ ? ? ?生成的classes是用C++的namespace來區分的。舉例:Open?would?be?in?the?namespace?foo::bar。
Java ? ? ?package用于Java的package,除非你單獨的指定一個option?java_package?在.proto文件中。
Python ? package是被忽略的,因為Python的modules是通過它們的文件位置來組織的。
Java ? ? ?package用于Java的package,除非你單獨的指定一個option?java_package?在.proto文件中。
Python ? package是被忽略的,因為Python的modules是通過它們的文件位置來組織的。
?
- Packages和name?
在protocol buffer中package名稱的方案看起來像C++,首先,最里面的范圍被搜索,然后搜索次一級的范圍,
每個package被認為在他的父package內。一個. (.foo.bar.Baz)意味著從最外層開始.
?
options
在一個proto文件中,還可以存在一些options。Options不能改變一個聲明的整體的意義,但是可以影響一定的上下文。
可用的options的完整list定義在 Google/protobuf/descriptor.proto
?
一些options是第一級的,意味著它們應該被寫在頂級范圍,而不是在任何message,enum,sercie的定義中。
一些options是message級別的,意味著它們應該被寫入message的描述中,
一些options是field-level級別的,意味著它們應該被寫入field的描述中,
options也可以被寫入enum類型中,enum的值,service類型 和service方法;
?
列舉了常用的options:
java_package(file option)
定義生成的java class的package。如果在proto文件中沒有明確的java_package選項,那么默認會使用package關鍵字指定的package名。
但是proto package通常不會好于Java packages,因為proto packages通常不會以domain名稱開始。
如果不生成java代碼,此選項沒有任何影響。
option java_package = "com.example.foo";
java_outer_classname:(file option)
指定想要生成的class名稱,如果此參數沒有指定的話,那么默認使用.proto文件名來做為類名,并且采用駝峰表示(比如:foo_bar.proto 為 FooBar.java)
如果不生成java代碼,此選項沒有影響。
option java_outer_classname = "Ponycopter";
optimize_for (file option)
可以設置為speed、code_size或者lite_runtime.
SPEED
:默認。protocol編譯器會生成classes代碼,提供了message類的序列化、轉換和其它通用操作。這個代碼是被高度優化過的。
CODE_SIZE:?
protocol編譯器會生成最小的classes,并且依賴共享、基于反射的代碼實現序列化、轉換和其它通用操作。生成的classes代碼小于speed,但是操作會慢一點。classes會實現跟SPEED模式一樣的公共API。這個模式通常用在一個應用程序包含了大量的proto文件,但是并不需要所有的代碼都執行得很快
LITE_RUNTIME:?
protocol編譯器會生成僅僅依賴 lite 運行庫(libprotobuf-lite代替libprotobuf)。lite運行時比全量庫小很多,省略了某種特性(如: descriptors and reflection)這個選項對于運行在像移動手機這種有約束平臺上的應用更有效。 編譯器仍然會對所有方法生成非常快的代碼實現,就像SPEED模式一樣。protocol編譯器會用各種語言來實現MessageList接口,但是這個接口僅僅提供了其它模式實現的Message接口的一部分方法子集。
例子
option?optimize_for? = ?CODE_SIZE ;
option?optimize_for? = ?CODE_SIZE ;
cc_generic_services, java_generic_services, py_generic_services (file options)
無論如何,protoc編譯器會生成基于C++,Java,Python的抽象service代碼,這些默認都是true。截至到2.3.0版本,RPC實現提供了代碼生成插件去生成代碼,不再使用抽象類。
//?This?file?relies?on?plugins?to?generate?service?code.
option?cc_generic_services?=?false ;
option?java_generic_services?=?false ;
option?py_generic_services?=?false ;
option?cc_generic_services?=?false ;
option?java_generic_services?=?false ;
option?py_generic_services?=?false ;
?
message_set_wire_format (message option)
如果設置為true,消息使用不同的二進制格式來兼容谷歌內部使用的稱為MessageSet的舊格式。用戶在google以外使用,將不再需要使用這個option。
消息必須按照以下聲明
message?Foo?{
??option?message_set_wire_format?=?true ;
??extensions?4?to?max ;
}
??option?message_set_wire_format?=?true ;
??extensions?4?to?max ;
}
packed (field option)
如果設置為true, 一個repeated的基本integer類型的field,會使用一種更加緊湊的壓縮編碼。請注意,在2.3.0版之前,protocol生成的解析邏輯收到未預期的壓縮的數據將會忽略掉。因此,改變一個已經存在的field,一定會破壞其線性兼容性。在2.3.0以后,這種改變就是安全的,解析邏輯可以識別壓縮和不壓縮的格式,但是,一定要小心那些使用原先舊版本的protocol的程序。
repeated?int32?samples?=?4?
[
packed=true
]
;
deprecated (field option):
如果設置為true,表示這個field被廢棄,應該使用新代碼。大多數語言中,這個沒有任何影響。在java中,會生成@Deprecated的注釋。未來,其它語言代碼在field的訪問方法上也會生成相應的注釋。
optional?int32?old_field?=?6?
[
deprecated=true
]
;
?
- 自定義options
?
protocol buffer還允許你自定義options。這是個高級特性,大多數人并不需要。options其實都定義在 google/protobuf/descriptor.proto文件中。
自定義的options是簡單的,繼承這些messages
import?"google/protobuf/descriptor.proto"
;
extend?google.protobuf.MessageOptions?{
??optional?string?my_option?=?51234 ;
}
message?MyMessage?{
??option?(my_option)?=?"Hello?world!" ;
}
extend?google.protobuf.MessageOptions?{
??optional?string?my_option?=?51234 ;
}
message?MyMessage?{
??option?(my_option)?=?"Hello?world!" ;
}
?
這里我們定義了一個message級別的消息選項,當使用這個options的時候,選項的名稱必須用括號括起來,以表明它是一個extension。
我們在C++中讀取my_option的值就像下面這樣:
string
?value?=?MyMessage::descriptor()->options().GetExtension(my_option);
這里,MyMessage::descriptor()->options()返回的MessageOptions protocol類型 message。
讀取自定義就如同讀取繼承屬性一樣。
在Java中
String?value?=?MyProtoFile.MyMessage.getDescriptor().getOptions().getExtension(MyProtoFile.myOption);
自定義options可以對任何message的組成元素進行定義
import?"google/protobuf/descriptor.proto"
;
extend?google.protobuf.FileOptions?{
??optional?string?my_file_option?=?50000 ;
}
extend?google.protobuf.MessageOptions?{
??optional?int32?my_message_option?=?50001 ;
}
extend?google.protobuf.FieldOptions?{
??optional?float?my_field_option?=?50002 ;
}
extend?google.protobuf.EnumOptions?{
??optional?bool?my_enum_option?=?50003 ;
}
extend?google.protobuf.EnumValueOptions?{
??optional?uint32?my_enum_value_option?=?50004 ;
}
extend?google.protobuf.ServiceOptions?{
??optional?MyEnum?my_service_option?=?50005 ;
}
extend?google.protobuf.MethodOptions?{
??optional?MyMessage?my_method_option?=?50006 ;
}
option?(my_file_option)?=?"Hello?world!" ;
message?MyMessage?{
??option?(my_message_option)?=?1234 ;
??optional?int32?foo?=?1? [ (my_field_option)?=?4.5 ] ;
??optional?string?bar?=?2 ;
}
enum?MyEnum?{
??option?(my_enum_option)?=?true ;
??FOO?=?1? [ (my_enum_value_option)?=?321 ] ;
??BAR?=?2 ;
}
message?RequestType?{}
message?ResponseType?{}
service?MyService?{
??option?(my_service_option)?=?FOO ;
??rpc?MyMethod(RequestType)?returns(ResponseType)?{
????//?Note:??my_method_option?has?type?MyMessage.??We?can?set?each?field
????//???within?it?using?a?separate? " option " ?line.
????option?(my_method_option).foo?=?567 ;
????option?(my_method_option).bar?=?"Some?string" ;
??}
}
extend?google.protobuf.FileOptions?{
??optional?string?my_file_option?=?50000 ;
}
extend?google.protobuf.MessageOptions?{
??optional?int32?my_message_option?=?50001 ;
}
extend?google.protobuf.FieldOptions?{
??optional?float?my_field_option?=?50002 ;
}
extend?google.protobuf.EnumOptions?{
??optional?bool?my_enum_option?=?50003 ;
}
extend?google.protobuf.EnumValueOptions?{
??optional?uint32?my_enum_value_option?=?50004 ;
}
extend?google.protobuf.ServiceOptions?{
??optional?MyEnum?my_service_option?=?50005 ;
}
extend?google.protobuf.MethodOptions?{
??optional?MyMessage?my_method_option?=?50006 ;
}
option?(my_file_option)?=?"Hello?world!" ;
message?MyMessage?{
??option?(my_message_option)?=?1234 ;
??optional?int32?foo?=?1? [ (my_field_option)?=?4.5 ] ;
??optional?string?bar?=?2 ;
}
enum?MyEnum?{
??option?(my_enum_option)?=?true ;
??FOO?=?1? [ (my_enum_value_option)?=?321 ] ;
??BAR?=?2 ;
}
message?RequestType?{}
message?ResponseType?{}
service?MyService?{
??option?(my_service_option)?=?FOO ;
??rpc?MyMethod(RequestType)?returns(ResponseType)?{
????//?Note:??my_method_option?has?type?MyMessage.??We?can?set?each?field
????//???within?it?using?a?separate? " option " ?line.
????option?(my_method_option).foo?=?567 ;
????option?(my_method_option).bar?=?"Some?string" ;
??}
}
如果想使用在package里面的自定義的option,必須要option前使用包名,如下
//?foo.proto
import?"google/protobuf/descriptor.proto" ;
package?foo ;
extend?google.protobuf.MessageOptions?{
??optional?string?my_option?=?51234 ;
}
//?bar.proto
import?"foo.proto" ;
package?bar ;
message?MyMessage?{
??option?(foo.my_option)?=?"Hello?world!" ;
}
import?"google/protobuf/descriptor.proto" ;
package?foo ;
extend?google.protobuf.MessageOptions?{
??optional?string?my_option?=?51234 ;
}
//?bar.proto
import?"foo.proto" ;
package?bar ;
message?MyMessage?{
??option?(foo.my_option)?=?"Hello?world!" ;
}
?
最后一件事:既然自定義的options是extensions,他們必須指定field number就像其它field或者extension一樣。如果你要在公共應用中使用自定義的options,那么一定要確認你的field numbers是全局唯一的
你能通過多選項帶有一個extension 把它們放入一個子message中
message?FooOptions?{
??optional?int32?opt1?=?1 ;
??optional?string?opt2?=?2 ;
}
extend?google.protobuf.FieldOptions?{
??optional?FooOptions?foo_options?=?1234 ;
}
//?usage:
message?Bar?{
??optional?int32?a?=?1? [ (foo_options.opt1)?=?123,?(foo_options.opt2)?=?"baz" ] ;
? ?//?alternative?aggregate?syntax?(uses?TextFormat):
??optional?int32?b?=?2? [ (foo_options)?=?{?opt1:?123?opt2:?"baz"?} ] ;
}
??optional?int32?opt1?=?1 ;
??optional?string?opt2?=?2 ;
}
extend?google.protobuf.FieldOptions?{
??optional?FooOptions?foo_options?=?1234 ;
}
//?usage:
message?Bar?{
??optional?int32?a?=?1? [ (foo_options.opt1)?=?123,?(foo_options.opt2)?=?"baz" ] ;
? ?//?alternative?aggregate?syntax?(uses?TextFormat):
??optional?int32?b?=?2? [ (foo_options)?=?{?opt1:?123?opt2:?"baz"?} ] ;
}
?
?
生成class代碼
為了生成java、python、C++代碼,你需要運行protoc編譯器 protoc 編譯.proto文件。
編譯器運行命令:
protoc?--proto_path=IMPORT_PATH?--cpp_out=DST_DIR?--java_out=DST_DIR?--python_out=DST_DIR?path/to/file.proto
import_path 查找proto文件的目錄,如果省略的話,就是當前目錄。存在多個引入目錄的話,可以使用--proto_path參數來多次指定,
-I=IMPORT_PATH就是--proto_path的縮寫
輸出目錄
--cpp_out ? ? ? 生成C++代碼在DST_DIR目錄
--java_out ? ? ?生成Java代碼在DST_DIR目錄
--python_out ? ?生成Python代碼在DST_DIR目錄
有個額外的好處,如果DST是.zip或者.jar結尾,那么編譯器將會按照給定名字輸入到一個zip壓縮格式的文件中。
輸出到.jar會有一個jar指定的manifest文件。注意?
如果輸出文件已經存在,它將會被覆蓋;編譯器的智能不足以自動添加文件到一個存在的壓縮文件中。
你必須提供一個或者多個.proto文件用作輸入。雖然文件命名關聯到當前路徑,每個文件必須在import_path路徑中一邊編譯器能規定它的規范名稱
更新message
更新message
如果一個message 不再滿足所有需要,需要對字段進行調整.(舉例:對message增加一個額外的字段,但是仍然有支持舊格式message的代碼在運行)
要注意以下幾點:
1、不要修改已經存在字段的數字順序標示
1、不要修改已經存在字段的數字順序標示
2、可以增加optional或者repeated的新字段。這么做以后,所有通過舊格式message序列化的數據都可以通過新代碼來生成對應的對象,正如他們不會丟失任何required元素。
你應該為這些元素添加合理的默認值,以便新代碼可以與舊代碼生成的消息交互。 新代碼創建的消息中舊代碼不存在的字段,在解析的時候,舊代碼會忽略掉新增的字段。
無論如何,未知的field不會被丟棄,如果message晚點序列化,為。
注意 未知field對于Python來說當前不可用。
3、非required字段都可以轉為extension ,反之亦然,只要type和number保持不變。
4、int32, uint32, int64, uint64, and bool 是全兼容的。這意味著你能改變一個field從這些類型中的一個改變為另一個,而不用考慮會打破向前、向后兼容性。
如果一個數字是通過網絡傳輸而來的相應類型轉換,你將會遇到type在C++中遇到的問題(e.g. if a 64-bit number is read as an int32, it will be truncated to 32 bits) ? ? ?
5、sint32 and sint64 彼此兼容,但是不能兼容其它integer類型.
6、string and bytes 在UTF-8編碼下是兼容的.?
7、如果bytes包含一個message的編碼,內嵌message與bytes兼容.
8、fixed32 兼容 sfixed32, ?fixed64 兼容 sfixed64.
9、optional 兼容 repeated. 用一個repeat字段的編碼結果作為輸入,認為這個字段是可選擇的客戶端會這樣處理,如果是原始類型的話,獲得最后的輸入作為相應的option值;如果是message 類型,合并所有輸入元素.?
10、更改默認值通常是OK的.要記得默認值并不會通過網絡發送,如果一個程序接受一個特定字段沒有設置值的消息,應用將會使用自己的版本協議定義的默認值,不會看見發送者的默認值.?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
