Protocol Buffers學習(4):更多訊息型別

大大怪發表於2017-05-23

介紹一下訊息的不同型別和引用

使用複雜訊息型別

您可以使用其他訊息型別作為欄位型別。例如,假設你想在每個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檔案中定義了怎麼解決呢?

你可以通過import引入其他的.proto檔案:

import "myproject/other_protos.proto";複製程式碼

注意

接上邊的例子,假如a.proto引入了b.proto,但是b.proto更換了位置,路徑變成了test/b.proto(隨便舉例),我們有兩種解決辦法:

  1. 修改a.proto中的import語句,直接import "test/b.proto"
  2. b.proto檔案原來的位置,建立一個b.proto檔案,檔案內容為import public "test/b.proto",就可以了

importproto2proto3都適用

巢狀型別

您可以在其他訊息型別中定義和使用訊息型別,如下,Result訊息定義在SearchResponse訊息中:

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

如果想重複使用Result,可以用Parent.Type的方式使用:

message AnotherResponse {
    SearchResponse.Result res = 1;
}複製程式碼

修改更新現有的訊息格式

修改時要注意的規則:

  1. 不要改變已經存在欄位的標籤
  2. 新增一個欄位時,舊的訊息將會收到這個欄位的預設值
  3. 刪除一個欄位時,記得把該欄位的標籤新增到reserved
  4. int32,uint32,int64,uint64和bool都是相容的。這意味著您可以將這些型別之一的欄位更改為另一個,而不會破壞前向或後向相容性。轉換過程相當於C ++中將該數字轉換為該型別(例如,如果將64位數字讀為int32, 它將被截斷到32位)
  5. sint32和sint64相互相容,但與其他整數型別不相容
  6. 只要位元組是有效的UTF-8,字串和位元組是相容的
  7. 巢狀訊息(message)與包含訊息的編碼版本的位元組(bytes)相容【表述不清,歡迎大家評論指正】
  8. fixed32與sfixed32相容,fixed64與sfixed64相容
  9. 列舉相容int32,uint32,int64和uint64(請注意,如果值不合適,那麼值將被截斷)。 但是請注意,客戶端程式碼可以在訊息反序列化時對它們進行不同的處理:例如,訊息中將保留無法識別的proto3列舉型別,但是當訊息反序列化時,如何處理和使用的程式語言相關。 Int欄位始終保持其值

Any型別

any型別時谷歌protobuf內建的一個型別,通用型別,使用的時候需要匯入google/protbuf/any.proto

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  repeated google.protobuf.Any details = 2;
}複製程式碼

Oneof型別

Oneof結構中有多個欄位,但是同一時刻只有一個欄位生效

定義oneof結構

message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}複製程式碼

oneof中可以是任意型別,除了repeated 欄位

生成程式碼之後,也會對oneof欄位生成getter,setter方法,但是出來的值需要你自己判斷一下

Maps 型別

如果你要定義一個map,protobuf提供了一個語法:

map<key_type, value_type> map_field = N;複製程式碼

例如

map<string, Project> projects = 3;複製程式碼

注意事項

  • Map欄位不能是repeated
  • Map中的集合是無序的
  • .proto檔案生成時,map按key排序
  • 解析或者合併時,後邊的會覆蓋前邊的

packages語法

你可以新增一個可選標識package.proto檔案中。用來防止命名衝突

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

在使用這條訊息的時候需要加上package名字

message Foo {
  ...
  foo.bar.Open open = 1;
  ...
}複製程式碼

相關文章