日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

什么是 Protobuf

Protobuf是Protocol Buffers的簡(jiǎn)稱,它是google公司開發(fā)的一種數(shù)據(jù)描述語(yǔ)言,用于描述一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,并于2008年對(duì)外開源。Protobuf可以用于結(jié)構(gòu)化數(shù)據(jù)串行化,或者說(shuō)序列化。它的設(shè)計(jì)非常適用于在網(wǎng)絡(luò)通訊中的數(shù)據(jù)載體,很適合做數(shù)據(jù)存儲(chǔ)或 RPC 數(shù)據(jù)交換格式,它序列化出來(lái)的數(shù)據(jù)量少再加上以 K-V 的方式來(lái)存儲(chǔ)數(shù)據(jù),對(duì)消息的版本兼容性非常強(qiáng),可用于通訊協(xié)議、數(shù)據(jù)存儲(chǔ)等領(lǐng)域的語(yǔ)言無(wú)關(guān)、平臺(tái)無(wú)關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式。開發(fā)者可以通過(guò)Protobuf附帶的工具生成代碼并實(shí)現(xiàn)將結(jié)構(gòu)化數(shù)據(jù)序列化的功能。

Protobuf中最基本的數(shù)據(jù)單元是message,是類似Go語(yǔ)言中結(jié)構(gòu)體的存在。在message中可以嵌套message或其它的基礎(chǔ)數(shù)據(jù)類型的成員。

教程中將描述如何用protocol buffer語(yǔ)言構(gòu)造你的protocol buffer數(shù)據(jù),包括.proto文件的語(yǔ)法以及如何通過(guò).proto文件生成數(shù)據(jù)訪問(wèn)類。教程中使用的是proto3版本的protocol buffer語(yǔ)言。

定義Message

首先看一個(gè)簡(jiǎn)單的例子,比如說(shuō)你定義一個(gè)搜索請(qǐng)求的message,每一個(gè)搜索請(qǐng)求會(huì)包含一個(gè)搜索的字符串,返回第幾頁(yè)的結(jié)果,以及結(jié)果集的大小。在.proto文件中定義如下:

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

  • .proto文件的第一行指定了使用proto3語(yǔ)法。如果省略protocol buffer編譯器默認(rèn)使用proto2語(yǔ)法。他必須是文件中非空非注釋行的第一行。
  • SearchRequest定義中指定了三個(gè)字段(name/value鍵值對(duì)),每個(gè)字段都會(huì)有名稱和類型。

指定字段類型

上面的例子中,所有的字段都是標(biāo)量類型的兩個(gè)整型(page_number和result_per_page)和一個(gè)字符串型(query)。不過(guò)你還可以給字段指定復(fù)合類型,包括枚舉類型和其他message類型

指定字段編號(hào)

在message定義中每個(gè)字段都有一個(gè)唯一的編號(hào),這些編號(hào)被用來(lái)在二進(jìn)制消息體中識(shí)別你定義的這些字段,一旦你的message類型被用到后就不應(yīng)該在修改這些編號(hào)了。注意在將message編碼成二進(jìn)制消息體時(shí)字段編號(hào)1-15將會(huì)占用1個(gè)字節(jié),16-2047將占用兩個(gè)字節(jié)。所以在一些頻繁使用用的message中,你應(yīng)該總是先使用前面1-15字段編號(hào)。

你可以指定的最小編號(hào)是1,最大是2E29 - 1(536,870,911)。其中19000到19999是給protocol buffers實(shí)現(xiàn)保留的字段標(biāo)號(hào),定義message時(shí)不能使用。同樣的你也不能重復(fù)使用任何當(dāng)前message定義里已經(jīng)使用過(guò)和預(yù)留的字段編號(hào)。

定義字段的規(guī)則

message的字段必須符合以下規(guī)則:

  • singular:一個(gè)遵循singular規(guī)則的字段,在一個(gè)結(jié)構(gòu)良好的message消息體(編碼后的message)可以有0或1個(gè)該字段(但是不可以有多個(gè))。這是proto3語(yǔ)法的默認(rèn)字段規(guī)則。(這個(gè)理解起來(lái)有些晦澀,舉例來(lái)說(shuō)上面例子中三個(gè)字段都是singular類型的字段,在編碼后的消息體中可以有0或者1個(gè)query字段,但不會(huì)有多個(gè)。)
  • repeated:遵循repeated規(guī)則的字段在消息體重可以有任意多個(gè)該字段值,這些值的順序在消息體重可以保持(就是數(shù)組類型的字段)

添加更多消息類型

在單個(gè).proto文件中可以定義多個(gè)message,這在定義多個(gè)相關(guān)message時(shí)非常有用。比如說(shuō),我們定義SearchRequest對(duì)應(yīng)的響應(yīng)message SearchResponse ,把它加到之前的.proto文件中。

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

添加注釋

.proto文件中的注釋和C,C++的注釋風(fēng)格相同,使用// 和 / ... /

/* 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.
}

保留字段

當(dāng)你刪掉或者注釋掉message中的一個(gè)字段時(shí),未來(lái)其他開發(fā)者在更新message定義時(shí)就可以重用之前的字段編號(hào)。如果他們意外載入了老版本的.proto文件將會(huì)導(dǎo)致嚴(yán)重的問(wèn)題,比如數(shù)據(jù)損壞、隱私泄露等。一種避免問(wèn)題發(fā)生的方式是指定保留的字段編號(hào)和字段名稱。如果未來(lái)有人用了這些字段標(biāo)識(shí)那么在編譯時(shí)protocol buffer的編譯器會(huì)報(bào)錯(cuò)。

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

proto會(huì)生成什么代碼

當(dāng)使用protocol buffer編譯器編譯.proto文件時(shí),編譯器會(huì)根據(jù)你在.proto文件中定義的message類型生成指定編程語(yǔ)言的代碼。生成的代碼包括訪問(wèn)和設(shè)置字段值、格式化message類型到輸出流,從輸入流解析出message等。

  • For C++, the compiler generates a .h and .cc file from each .proto, with a class for each message type described in your file.
  • For JAVA, the compiler generates a .java file with a class for each message type, as well as a special Builderclasses for creating message class instances.
  • Python is a little different – the Python compiler generates a module with a static descriptor of each message type in your .proto, which is then used with a metaclass to create the necessary Python data access class at runtime.
  • For Go, the compiler generates a .pb.go file with a type for each message type in your file.
  • For Ruby, the compiler generates a .rb file with a Ruby module containing your message types.
  • For Objective-C, the compiler generates a pbobjc.h and pbobjc.m file from each .proto, with a class for each message type described in your file.
  • For C#, the compiler generates a .cs file from each .proto, with a class for each message type described in your file.
  • For Dart, the compiler generates a .pb.dart file with a class for each message type in your file.

標(biāo)量類型

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

默認(rèn)值

當(dāng)時(shí)一個(gè)被編碼的message體中不存在某個(gè)message定義中的singular字段時(shí),在message體解析成的對(duì)象中,相應(yīng)字段會(huì)被設(shè)置為message定義中該字段的默認(rèn)值。默認(rèn)值依類型而定:

  • 對(duì)于字符串,默認(rèn)值為空字符串。
  • 對(duì)于字節(jié),默認(rèn)值為空字節(jié)。
  • 對(duì)于bools,默認(rèn)值為false。
  • 對(duì)于數(shù)字類型,默認(rèn)值為零。
  • 對(duì)于枚舉,默認(rèn)值是第一個(gè)定義的枚舉值,該值必須為0。
  • 對(duì)于消息字段,未設(shè)置該字段。它的確切值取決于語(yǔ)言。有關(guān)詳細(xì)信息,請(qǐng)參閱代碼生成指南。

枚舉類型

在定義消息類型時(shí),您可能希望其中一個(gè)字段只有一個(gè)預(yù)定義的值列表中的值。例如,假設(shè)您要為每個(gè)SearchRequest添加corpus字段,其中corpus可以是UNIVERSAL,WEB,IMAGES,LOCAL,NEWS,PRODUCTS或VIDEO。您可以非常簡(jiǎn)單地通過(guò)向消息定義添加枚舉,并為每個(gè)可能的枚舉值值添加常量來(lái)實(shí)現(xiàn)。

在下面的例子中,我們添加了一個(gè)名為Corpus的枚舉類型,和一個(gè)Corpus類型的字段:

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

如你所見,Corpus枚舉的第一個(gè)常量映射到了0:所有枚舉定義都需要包含一個(gè)常量映射到0并且作為定義的首行,這是因?yàn)椋?/p>

  • 必須有0值,這樣我們就可以將0作為枚舉的默認(rèn)值。
  • proto2語(yǔ)法中首行的枚舉值總是默認(rèn)值,為了兼容0值必須作為定義的首行。

使用其他Message類型

可以使用其他message類型作為字段的類型,假設(shè)你想在每個(gè)SearchResponse消息中攜帶類型為Result的消息,

你可以在同一個(gè).proto文件中定義一個(gè)Result消息類型,然后在SearchResponse中指定一個(gè)Result類型的字段。

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

導(dǎo)入消息定義

在上面的示例中,Result消息類型在與SearchResponse相同的文件中定義 - 如果要用作字段類型的消息類型已在另一個(gè).proto文件中定義,該怎么辦?

您可以通過(guò)導(dǎo)入來(lái)使用其他.proto文件中的定義。要導(dǎo)入另一個(gè).proto的定義,請(qǐng)?jiān)谖募敳刻砑右粋€(gè)import語(yǔ)句:

import "myproject/other_protos.proto";

默認(rèn)情況下,您只能使用直接導(dǎo)入的.proto文件中的定義。但是,有時(shí)你可能需要將.proto文件移動(dòng)到新位置。現(xiàn)在,你可以在舊位置放置一個(gè)虛擬.proto文件,在文件中使用import public語(yǔ)法將所有導(dǎo)入轉(zhuǎn)發(fā)到新位置,而不是直接移動(dòng).proto文件并在一次更改中更新所有調(diào)用點(diǎn)。任何導(dǎo)入包含import public語(yǔ)句的proto文件的人都可以傳遞依賴導(dǎo)入公共依賴項(xiàng)。例如

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

編譯器會(huì)在通過(guò)命令行參數(shù)-I或者--proto-path中指定的文件夾中搜索.proto文件,如果沒有提供編譯器會(huì)在喚其編譯器的目錄中進(jìn)行搜索。通常來(lái)說(shuō)你應(yīng)該將--proto-path的值設(shè)置為你項(xiàng)目的根目錄,并對(duì)所有導(dǎo)入使用完全限定名稱。

使用proto2的消息類型

可以導(dǎo)入proto2版本的消息類型到proto3的消息類型中使用,當(dāng)然也可以在proto2消息類型中導(dǎo)入proto3的消息類型。但是proto2的枚舉類型不能直接應(yīng)用到proto3的語(yǔ)法中。

嵌套消息類型

消息類型可以被定義和使用在其他消息類型中,下面的例子里Result消息被定義在SearchResponse消息中

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

如果你想在外部使用定義在父消息中的子消息,使用Parent.Type引用他們

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

你可以嵌套任意多層消息

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

更新Message

如果一個(gè)現(xiàn)存的消息類型不再滿足你當(dāng)前的需求--比如說(shuō)你希望在消息中增加一個(gè)額外的字段--但是仍想使用由舊版的消息格式生成的代碼,不用擔(dān)心!只要記住下面的規(guī)則,在更新消息定義的同時(shí)又不破壞現(xiàn)有的代碼就非常簡(jiǎn)單。

  • 不要更改任何已存字段的字段編號(hào)。
  • 如果添加了新字段,任何由舊版消息格式生成的代碼所序列化的消息,仍能被依據(jù)新消息格式生成的代碼所解析。你應(yīng)該記住這些元素的默認(rèn)值這些新生成的代碼就能夠正確地與由舊代碼序列化創(chuàng)建的消息交互了。類似的,新代碼創(chuàng)建的消息也能由舊版代碼解析:舊版消息(二進(jìn)制)在解析時(shí)簡(jiǎn)單地忽略了新增的字段,查看下面的未知字段章節(jié)了解更多。
  • 只要在更新后的消息類型中不再重用字段編號(hào),就可以刪除該字段。你也可以重命名字段,比如說(shuō)添加OBSOLETE_前綴或者將字段編號(hào)設(shè)置為reserved,這些未來(lái)其他用戶就不會(huì)意外地重用該字段編號(hào)了。

未知字段

未知字段是格式良好的協(xié)議緩沖區(qū)序列化數(shù)據(jù),表示解析器無(wú)法識(shí)別的字段。例如,當(dāng)舊二進(jìn)制文件解析具有新字段的新二進(jìn)制文件發(fā)送的數(shù)據(jù)時(shí),這些新字段將成為舊二進(jìn)制文件中的未知字段。

最初,proto3消息在解析期間總是丟棄未知字段,但在3.5版本中,我們重新引入了未知字段的保留以匹配proto2行為。在版本3.5及更高版本中,未知字段在解析期間保留,并包含在序列化輸出中。

映射類型

如果你想創(chuàng)建一個(gè)映射作為message定義的一部分,protocol buffers提供了一個(gè)簡(jiǎn)易便利的語(yǔ)法

map<key_type, value_type> map_field = N;

key_type可以是任意整數(shù)或者字符串(除了浮點(diǎn)數(shù)和bytes以外的所有標(biāo)量類型)。注意enum不是一個(gè)有效的key_type。value_type可以是除了映射以外的任意類型(意思是protocol buffers的消息體中不允許有嵌套map)。

舉例來(lái)說(shuō),假如你想創(chuàng)建一個(gè)名為projects的映射,每一個(gè)Project消息關(guān)聯(lián)一個(gè)字符串鍵,你可以像如下來(lái)定義:

map<string, Project> projects = 3;
  • 映射里的字段不能是follow repeated規(guī)則的(意思是映射里字段的值不能是數(shù)組)。
  • 映射里的值是無(wú)序的,所以不能依賴映射里元素的順序。
  • 生成.proto的文本格式時(shí),映射按鍵排序。數(shù)字鍵按數(shù)字排序。
  • 從線路解析或合并時(shí),如果有重復(fù)的映射鍵,則使用最后看到的鍵。從文本格式解析映射時(shí),如果存在重復(fù)鍵,則解析可能會(huì)失敗。
  • 如果未給映射的字段指定值,字段被序列化時(shí)的行為依語(yǔ)言而定。在C++, Java和Python中字段類型的默認(rèn)值會(huì)被序列化作為字段值,而其他語(yǔ)言則不會(huì)。

給Message加包名

你可以在.proto文件中添加一個(gè)可選的package符來(lái)防止消息類型之前的名稱沖突。

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

在定義message的字段時(shí)像如下這樣使用package名稱

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

package符對(duì)生成代碼的影響視編程語(yǔ)言而定

定義服務(wù)

如果想消息類型與RPC(遠(yuǎn)程過(guò)程調(diào)用)系統(tǒng)一起使用,你可以在.proto文件中定義一個(gè)RPC服務(wù)接口,然后protocol buffer編譯器將會(huì)根據(jù)你選擇的編程語(yǔ)言生成服務(wù)接口代碼和stub,加入你要定義一個(gè)服務(wù),它的一個(gè)方法接受SearchRequest消息返回SearchResponse消息,你可以在.proto文件中像如下示例這樣定義它:

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

與protocol buffer 一起使用的最簡(jiǎn)單的RPC系統(tǒng)是gRPC:一種由Google開發(fā)的語(yǔ)言和平臺(tái)中立的開源RPC系統(tǒng)。 gRPC特別適用于protocol buffer,并允許您使用特殊的protocol buffer編譯器插件直接從.proto文件生成相關(guān)的RPC代碼。

如果你不想使用gRPC,可以使用自己實(shí)現(xiàn)的RPC系統(tǒng),更多關(guān)于實(shí)現(xiàn)RPC系統(tǒng)的細(xì)節(jié)可以在Proto2 Language Guide中找到。

JSON編解碼

Proto3支持JSON中的規(guī)范編碼,使得在系統(tǒng)之間共享數(shù)據(jù)變得更加容易。在下表中逐個(gè)類型地列出了編碼規(guī)則。

如果JSON編碼數(shù)據(jù)中缺少某個(gè)值,或者其值為null,則在解析為protocol buffer時(shí),它將被解釋為相應(yīng)的默認(rèn)值。如果字段在protocol buffer中具有默認(rèn)值,則默認(rèn)情況下將在JSON編碼的數(shù)據(jù)中省略該字段以節(jié)省空間。編寫編解碼實(shí)現(xiàn)可以覆蓋這個(gè)默認(rèn)行為在JSON編碼的輸出中保留具有默認(rèn)值的字段的選項(xiàng)。

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

生成代碼

要生成Java,Python,C ++,Go,Ruby,Objective-C或C#代碼,你需要使用.proto文件中定義的消息類型,你需要在.proto上運(yùn)行protocol buffer編譯器protoc。如果尚未安裝編譯器,請(qǐng)下載該軟件包并按照README文件中的說(shuō)明進(jìn)行操作。對(duì)于Go,還需要為編譯器安裝一個(gè)特殊的代碼生成器插件:你可以在GitHub上的golang/protobuf項(xiàng)目中找到這個(gè)插件和安裝說(shuō)明。

編譯器像下面這樣喚起:

谷歌最流行的序列化格式:Protobuf 語(yǔ)言指南

 

  • IMPORT_PATH指定了在解析import命令時(shí)去哪里搜索.proto文件,如果忽略將在當(dāng)前工作目錄進(jìn)行查找,可以通過(guò)傳遞多次--proto-path參數(shù)來(lái)指定多個(gè)import目錄,他們將會(huì)按順序被編譯器搜索。-I=IMPORT_PATH是--proto_path的簡(jiǎn)短形式。
  • 你可以提供一個(gè)或多個(gè)輸出命令:
  • --cpp_out generates C++ code in DST_DIR. See the C++ generated code referencefor more.
  • --java_out generates Java code in DST_DIR. See the Java generated code referencefor more.
  • --python_out generates Python code in DST_DIR. See the Python generated code reference for more.
  • --go_out generates Go code in DST_DIR. See the Go generated code reference for more.
  • --ruby_out generates Ruby code in DST_DIR. Ruby generated code reference is coming soon!
  • --objc_out generates Objective-C code in DST_DIR. See the Objective-C generated code reference for more.
  • --csharp_out generates C# code in DST_DIR. See the C# generated code referencefor more.
  • --php_out generates PHP code in DST_DIR. See the PHP generated code referencefor more.
  • 必須提供一個(gè)或多個(gè).proto文件作為輸入??梢砸淮沃付ǘ鄠€(gè).proto文件。雖然文件是相對(duì)于當(dāng)前目錄命名的,但每個(gè)文件必須存在于其中一個(gè)IMPORT_PATH中,以便編譯器可以確定其規(guī)范名稱。

原文鏈接:https://segmentfault.com/a/1190000020386857

本文作者:KevinYan,原創(chuàng)授權(quán)發(fā)布

分享到:
標(biāo)簽:Protobuf
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定