定義消息類型
首先讓我們看一個非常簡單的例子. 假設要定義搜索請求消息格式, 其中每個搜索請求都有一個查詢字符串, 您感興趣的特定結果頁面以及每頁的一些結果. 這是用于定義消息類型的 .proto 文件.
syntax = "proto3";
message SearchRequest {
string query = 1;
protobuf支持的數據類型?int32 page_number = 2;
int32 result_per_page = 3;
}
注意以下幾點:
該文件的第一行指定使用 proto3 語法; 如果不寫則使用 proto2.
一個消息對應一個字段, 一個字段對應一個數據類型.
json和protobuf的區別?值得注意的是: 字段類型可以是枚舉或其他數據類型.
字段編號
比如 string query = 1; 字段, 1 就是字段編號(unique number).
字段編號的范圍為 1 到 536,870,911. 不能使用數字 19000 到 19999, 因為它們是為 Google Protobuf 保留的.
在同一個 .proto 文件中添加多個消息類型
message SearchRequest {
c語言string函數用法,string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
...
prototype和__proto__,}
保留字段
當定義好字段后, 在后續開發中發現某個字段根本沒用.
例如 string userName = 2; 字段, 這個時候最好不要進行注釋或刪除.
有可能以后加載相同的舊版本, 這可能會導致數據損壞, 隱私錯誤等. 確保不會發生這種情況的一種方法是指定要刪除的字段為保留字段.
message SubscribeReq {
json轉protobuf。reserved 2;
int32 subReqID = 1;
string userName = 2;
string productName = 3;
string address = 4;
}
c語言string函數有哪些、顧名思義, 就是此字段會被保留可能在以后會使用此字段. 使用關鍵字 reserved 表示要保留字段編號為 2.
上面代碼我們在生成 Java 文件的時候會出現 ubscribeReqPeoro.proto: Field "userName" uses reserved number 2 錯誤信息, 所以需要將 string userName = 2; 注釋, 或者刪除.
值得注意的是: 您不能在同一 reserved 語句中混合字段名稱和字段編號. 下面是表準格式:
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
c語言string類型輸入、}
指定字段規則
所指定的消息字段修飾符必須是如下之一:
singular: 一個格式良好的消息應該有0個或者1個這種字段 (但是不能超過1個).
repeated: 一個格式良好的消息中, 這種字段可以重復任意多次 (包括 0 次). 重復值的順序會被保留.
枚舉
python protobuf解析。當需要定義一個消息類型的時候, 可能想為一個字段指定某 “預定義值序列” 中的一個值.
例如, 假設要為每一個 SearchRequest 消息添加一個 corpus 字段, 而 corpus 的值可能是 UNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS 或 VIDEO 中的一個.
其實可以很容易地實現這一點: 通過向消息定義中添加一個枚舉 (enum) 并且為每個可能的值定義一個常量就可以了.
在下面的例子中, 在消息格式中添加了一個叫做 Corpus 的枚舉類型——它含有所有可能的值——以及一個類型為 Corpus 的字段:
message SearchRequest {
string query = 1;
c語言string頭文件?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;
}
值得注意的是:
每個枚舉類型必須將其第一個類型映射為 0, 這是因為:
必須有有一個 0 值, 我們可以用這個 0 值作為默認值.
這個零值必須為第一個元素, 為了兼容 proto2 語義, 枚舉類的第一個值總是默認值.
另外, 枚舉常量必須在 32 位整數范圍內, 并且盡量不要使用負數.
你可以通過將不同的枚舉常量指定為相同的值. 如果這樣做你需要將 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.
}
其它消息類型
你可以將其他消息類型用作字段類型. 例如, 假設在每一個 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 消息內, 如:
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;
}
}
}
導入定義
在上面的示例中, Result 和 SearchResponse 消息類型在同一文件中的, 如果要用作字段類型的消息類型在另一個 .proto 文件中定義, 該怎么辦?
可以 .proto 通過導入來使用其他文件中的定義. 需要在文件頂部添加 import 語句:
import "myproject/other_protos.proto";
默認情況下, 使用直接導入的 .proto 文件中的定義.
但是, 有時可能需要將 .proto 文件移動到新位置. 如果直接移動文件位置可能要修改許多代碼位置.
我們可以使用 import public 來解決這個問題.
實例代碼:
// new.proto
// All definitions are moved here
// old.proto
//This is the proto that all clients are importing.
import public“new.proto”;
import“other.proto”;
// client.proto
import "old.proto";
//您使用old.proto和new.proto中的定義,但不使用other.proto
Maps
如果要在數據定義中創建關聯映射, 協議緩沖區提供了一種方便的快捷方式語法:
map < key_type ,value_type > map_field = N ;
key_type 可以是任何整數或字符串類型.
value_type 可以是除了 map 的其他類型.
例如, 如果要創建項目映射, 其中每條 Project 消息都與字符串鍵相關聯, 則可以像下面這樣定義它:
map < string,Project > projects = 3;
值得注意的是: map 不能使用 repeated.
包
您可以向 .proto 文件添加 package 可選說明符, 以防止協議消息類型之間的名稱沖突.
package foo.bar;
message Open { ... }
然后, 您可以在定義消息類型的字段時使用包說明符:
message Foo {
...
foo.bar.Open open = 1;
...
}
Any (任意類型)
// new.proto
syntax = "proto3";
import "google/protobuf/any.proto";
message SearchRequest {
string query = 1;
int32 page_number = 2;
repeated google.protobuf.Any result_per_page = 3;
}
編譯的時候需要將 google/protobuf/any.proto 和 new.proto 文件放到一起. 要注意目錄結構.
然后執行下面命令進行編譯:
sudo ./protoc -I=/home/sc-ik/桌面/ --java_out=./java /home/sc-ik/桌面/*.proto
在對 result_per_page 進行賦值時, 需要用到 Any 類中的 public static Any pack(T message) 方法.
在 java 代碼中, 先創建 SearchRequest 對象, 然后對其他兩個屬性進行賦值.
New.SearchRequest.Builder searchRequest = New.SearchRequest.newBuilder();
searchRequest.setQuery("test");
searchRequest.setPageNumber(10086);
在對 result_per_page 進行賦值時, 需要注意: pack 方法的參數類型為 com.google.protobuf.Message 接口.
生成的 java 代碼中, 類是繼承自 GeneratedMessageV3.
public static final class SearchRequest extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:SearchRequest)
SearchRequestOrBuilder {
private static final long serialVersionUID = 0L;
但是如果將result_per_page 賦值為 SearchRequest, 應該怎么操作呢?
重點就是繼承的 GeneratedMessageV3 抽象類, 這個抽象類又繼承了 AbstractMessage 抽象類, 而 AbstractMessage 抽象類就是 com.google.protobuf.Message 接口的實現.
public abstract class AbstractMessage
// TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
extends AbstractMessageLite implements Message {
所以我們可以使用以下方法進行賦值.
searchRequest.addResultPerPage(
com.google.protobuf.Any.pack(
searchRequest.build()
)
);
pack() 方法我個人理解為序列化, 那么和他對應的是反序列化 unpack().
// 將接收到的字節數組飯序列化.
New.SearchRequest.Builder builder2 = New.SearchRequest.newBuilder().mergeFrom(bytes1);
// 獲取到 result_per_page 字段的值.
Any.Builder resultPerPageBuilder = builder2.getResultPerPageBuilder(0);
// 然后使用 unpack 將任意類型 進行反序列化, 得到想要的數據.
New.SearchRequest unpack1 = resultPerPageBuilder.build().unpack(New.SearchRequest.class);
編譯
編譯命令:
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/*.proto
如下:
sudo ./protoc -I=/home/sc-ik/桌面/ --java_out=./java /home/sc-ik/桌面/*.proto
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态