protobuf入門

ProtoBuf

參考網(wǎng)址:https://developers.google.com/protocol-buffers/docs/proto3

ProtoBuf是Google的與語言無關(guān)赡鲜,與平臺無關(guān)碟狞,可擴展的機制得问,用于對結(jié)構(gòu)化數(shù)據(jù)進行序列化–以XML為例榜旦,但更小,更快弛姜,更簡單柠硕。您定義要一次構(gòu)造數(shù)據(jù)的方式,然后可以使用生成的特殊源代碼輕松地使用各種語言在各種數(shù)據(jù)流中寫入和讀取結(jié)構(gòu)化數(shù)據(jù)总棵。

Defining A Message Type

定義一個消息格式

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  • 第一行:syntax = "proto3"; 如果你不指定的話鳍寂,默認使用proto2
  • SearchRequest定義了具體的三個屬性(name/value pairs),每個字段包含名稱和類型
Specifying Field Types

屬性類型是一個(scalar types)標(biāo)量類型,你可以自定義一個枚舉類型情龄,后面我們會提到這一點

Assigning Field Numbers

每一個信息有一個唯一的數(shù)值(unique number)

這個字段被用來定義message binary format消息二進制格式迄汛。并且一旦確定并使用了不應(yīng)該被改變。在1-15之間使用一個字節(jié)骤视,在16-2047使用兩個字節(jié)鞍爱。

最小的數(shù)字是1,最大的數(shù)字是2^29 - 1专酗,同時19000-19999是官方使用的字段睹逃,你也不可以使用

Specifying Field Rules

消息字段可以是以下兩種之一

  • singular:這個字段可以有0個或1個。這是proto3默認的
  • repeated:這個字段可以是0個或無線多個。repeated默認使用packed編碼
Adding More Message Types

你一個在一個.proto添加多個message

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

message SearchResponse {
 ...
}
Adding Comments

增加注釋

使用//或者/*...*/

/* SearchRequest represents a search query, with pagination options to
 * indicate which results to include in the response. */

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.
}
Reserved Fields

保留字段沉填,如果你更新了message疗隶,刪除了一些字段,并且將來有些人重用了這些number翼闹“弑牵可能會造成一些問題。你可以保留這些number(可能的話保留字段名)

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}
What's Generated From Your .proto?

For Go, the compiler generates a .pb.go file with a type for each message type in your file.

Scalar Value Types 標(biāo)量值類型
image-20210420144558956.png
Default Values(默認值)
  • Strings:""

  • Bytes:''

  • Bool:false

  • Numeric Types:0

  • Enums:默認值是第一個被定義的enum value猎荠,必須是0

  • 默認的repeated是一個空列表

Enumerations(枚舉)

在下面的示例中坚弱,我們添加了一個名為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;
}
  • 零值必須是第一個值关摇,必須有一個零值

你可以設(shè)置別名史汗,但必須將allow_alias設(shè)置為true

message MyMessage1 {
  enum EnumAllowingAlias {
    option allow_alias = true;
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 1;
  }
}
message MyMessage2 {
  enum EnumNotAllowingAlias {
    UNKNOWN = 0;
    STARTED = 1;
    // RUNNING = 1;  // Uncommenting this line will cause a compile error inside Google and a warning message outside.
  }
}

枚舉的值必須在32位證書內(nèi)

你可以設(shè)置枚舉的保留值
enum Foo {
  reserved 2, 15, 9 to 11, 40 to max;
  reserved "FOO", "BAR";
}
Using Other Message Types

你可以使用內(nèi)置的message作為其他message的字段

// 將Result內(nèi)置到SearchResponse
message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}
Importing Definitions 引入定義

你可以從其他proto引入message

import "myproject/other_protos.proto";

默認情況下,您只能使用直接導(dǎo)入的.proto文件中的定義拒垃。但是停撞,有時您可能需要將.proto文件移動到新位置。現(xiàn)在悼瓮,您可以直接在原始位置放置一個虛擬.proto文件戈毒,而不是直接移動.proto文件并一次更改所有呼叫站點,而是使用導(dǎo)入公共概念將所有導(dǎo)入轉(zhuǎn)發(fā)到新位置横堡。導(dǎo)入包含導(dǎo)入公共聲明的原型的任何人都可以可傳遞地依賴導(dǎo)入公共依賴項埋市。例如:

// 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";
// You use definitions from old.proto and new.proto, but not other.proto
Nested Types 內(nèi)嵌類型

你可以使用內(nèi)嵌類型

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

你也可以復(fù)用內(nèi)嵌類型

message SomeOtherMessage {
  SearchResponse.Result result = 1;
}

你可以隨便內(nèi)嵌

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;
    }
  }
}
Updating A Message Type

一些更新的規(guī)則https://developers.google.com/protocol-buffers/docs/proto3#updating

Unknown Fields

未命名類型是格式正確但解析器無法解析的字段,會被保留在序列化中

未知字段是格式正確的協(xié)議緩沖區(qū)序列化數(shù)據(jù)命贴,表示解析器無法識別的字段道宅。例如,當(dāng)舊二進制文件使用新字段解析新二進制文件發(fā)送的數(shù)據(jù)時胸蛛,這些新字段將成為舊二進制文件中的未知字段污茵。

Any

Any消息類型使您可以將消息用作嵌入類型,而無需定義它們的.proto葬项。 Any包含任意序列化消息(以字節(jié)為單位)以及URL泞当,URL作為該消息的類型并解析為該消息的類型的全局唯一標(biāo)識符。要使用Any類型民珍,您需要導(dǎo)入google / protobuf / any.proto襟士。

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  repeated google.protobuf.Any details = 2;
}
Oneof

如果你有一個message,并且包含有多個字段嚷量,并且你最多同時設(shè)置一個字段陋桂,你可以強迫使用oneof來節(jié)省內(nèi)存

它會將其他字段刪除

Using Oneof
message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}
Oneof Features
  • 設(shè)定一個oneof將會清楚其他的oneof,如果你有幾個oneof字段蝶溶,只有最后一個才有值
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message();   // Will clear name field.
CHECK(!message.has_name());
  • oneof 不能使用repeated
  • oneof也使用與反射
Backwards-compatibility issues

添加或刪除字段之一時請多加注意嗜历。如果檢查oneof的值返回None / NOT_SET,則可能意味著oneof尚未設(shè)置或已被設(shè)置為oneof的不同版本中的字段。由于無法知道導(dǎo)線上的未知字段是否是oneof的成員秸脱,因此無法分辨出兩者之間的區(qū)別落包。

Maps

如果你想創(chuàng)建一個map部蛇,可以使用以下語法

map<key_type, value_type> map_field = N;

map<string, Project> projects = 3;

Packages

你可以說增加一個可選擇的packageto.proto避免命名沖突

package foo.bar;
message Open { ... }

你可以使用包的字段

message Foo {
  ...
  foo.bar.Open open = 1;
  ...
}
Defining Services(定義服務(wù))

如果你想使用message來使用PRC摊唇,你可以定義PRC service在.proto中。

如果你有SearchRequestSearchResponse.

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}

附錄:

代碼生成規(guī)則:https://developers.google.com/protocol-buffers/docs/reference/go-generated

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涯鲁,一起剝皮案震驚了整個濱河市巷查,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抹腿,老刑警劉巖岛请,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異警绩,居然都是意外死亡崇败,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門肩祥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來后室,“玉大人,你說我怎么就攤上這事混狠“杜” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵将饺,是天一觀的道長贡避。 經(jīng)常有香客問我,道長予弧,這世上最難降的妖魔是什么刮吧? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮掖蛤,結(jié)果婚禮上皇筛,老公的妹妹穿的比我還像新娘。我一直安慰自己坠七,他們只是感情好水醋,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著彪置,像睡著了一般拄踪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拳魁,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天惶桐,我揣著相機與錄音,去河邊找鬼。 笑死姚糊,一個胖子當(dāng)著我的面吹牛贿衍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播救恨,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼贸辈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肠槽?” 一聲冷哼從身側(cè)響起擎淤,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤秸仙,失蹤者是張志新(化名)和其女友劉穎嘴拢,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寂纪,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡席吴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年孝冒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焕梅。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡迹鹅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贞言,到底是詐尸還是另有隱情斜棚,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布该窗,位于F島的核電站弟蚀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏酗失。R本人自食惡果不足惜义钉,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望规肴。 院中可真熱鬧捶闸,春花似錦夜畴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至央碟,卻和暖如春税灌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硬耍。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工垄琐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留边酒,地道東北人经柴。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像墩朦,于是被迫代替她去往敵國和親坯认。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容