【輕知識】(糙譯)Go使用proto3、官方示例代碼

個人覺得,有谷歌翻譯魄健,百度翻譯。加上自己的理解舰涌。自個看看官方文檔也還不錯秘蛔。
下面98%是谷歌翻譯跟百度翻譯的。剩余2%是我自己按照自己的理解岁忘。
免責聲明:粗糙翻譯辛慰,隨便看看哈。想糾正的干像。留言即可帅腌。本人水平有限。

Protocol Buffer Basics: Go

通過創(chuàng)建一個簡單的示例應用程序麻汰,它向您展示如何:

  • 在.proto文件中定義消息格式速客。
  • 使用協(xié)議緩沖區(qū)編譯器。
  • 使用Go協(xié)議緩沖區(qū)API來編寫和讀取消息五鲫。

"生成的代碼指南"
編碼參考
GO api參考

為何使用protobuf

假設我們的示例是一個非常簡單的“地址簿”應用程序溺职,可以在文件中讀取和寫入人員的聯(lián)系人詳細信息。地址簿中的每個人都有姓名位喂,ID浪耘,電子郵件地址和聯(lián)系電話號碼。

那么序列化和恢復這樣結構(序列化與反序列化)的幾種方法:

  • 使用gobs序列化Go數(shù)據(jù)結構塑崖。這是Go特定環(huán)境中的一個很好的解決方案七冲,但如果您需要與為其他平臺編寫的應用程序共享數(shù)據(jù),它將無法正常工作规婆。

  • 您可以發(fā)明一種特殊的方法將數(shù)據(jù)項編碼為單個字符串 - 例如將4個整數(shù)編碼為“12:3:-23:67”澜躺。這是一種簡單而靈活的方法蝉稳,雖然它確實需要編寫一次性編碼和解析代碼,并且解析會產生較小的運行時成本掘鄙。這最適合編碼非常簡單的數(shù)據(jù)耘戚。

  • 將數(shù)據(jù)序列化為XML。這種方法非常有吸引力操漠,因為XML(有點)是人類可讀的收津,并且有許多語言的綁定庫。如果您想與其他應用程序/項目共享數(shù)據(jù)颅夺,這可能是一個不錯的選擇朋截。然而,XML是眾所周知的空間密集型吧黄,并且編碼/解碼它會對應用程序造成巨大的性能損失部服。此外,導航XML DOM樹比通常在類中導航簡單字段要復雜得多拗慨。

協(xié)議緩沖區(qū)是一種靈活廓八、高效、自動化的解決方案赵抢,可以精確地解決這個問題剧蹂。使用協(xié)議緩沖區(qū),可以編寫要存儲的數(shù)據(jù)結構的.proto描述烦却。由此宠叼,協(xié)議緩沖區(qū)編譯器創(chuàng)建了一個類,該類用有效的二進制格式實現(xiàn)協(xié)議緩沖區(qū)數(shù)據(jù)的自動編碼和解析其爵。生成的類為組成協(xié)議緩沖區(qū)的字段提供getter和setter冒冬,并負責將協(xié)議緩沖區(qū)作為一個單元讀寫的詳細信息。重要的是摩渺,協(xié)議緩沖區(qū)格式支持隨著時間的推移擴展格式的思想简烤,這樣代碼仍然可以讀取用舊格式編碼的數(shù)據(jù)。

示例代碼https://github.com/protocolbuffers/protobuf/tree/master/examples

定義你的protocol 格式

要創(chuàng)建通訊簿應用程序摇幻,您需要從.proto文件開始横侦。.proto文件中的定義很簡單:為要序列化的每個數(shù)據(jù)結構添加消息,然后為消息中的每個字段指定名稱和類型绰姻。在我們的示例中枉侧,定義消息的.proto文件是addressbook.proto。
.proto文件以包聲明開頭狂芋,這有助于防止不同項目之間的命名沖突棵逊。

syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto"

在go中,包名就是作為Go的包名银酗。除非你指定了一個go_package(編譯時可以指定go_package)辆影。你要是提供了go_package ,你定義的包名要避免與非Go語言的Protobuf 的命名空間的沖突黍特。

vscode 可以按照proto3的插件蛙讥,這樣編輯起來比較方便。

下面灭衷,你有了你的消息定義次慢。一個消息是包含一組類型字段的聚合。許多標準的簡單數(shù)據(jù)類型都可以作為字段類型翔曲,包括bool迫像,int32, float瞳遍,double闻妓,和string。您還可以使用其他消息類型作為字段類型掠械,為郵件添加更多結構由缆。

message Person {
    string name  = 1;
    int32 id = 2;
    string email = 3;

    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        string number = 1;
        PhoneType type =2;
    }
    repeated PhoneNumber phones = 4;
    google.protobuf.Timestamp last_updated = 5;
}

message AddressBook {
    repeated Person people = 1;
}

在上面的示例中,Person消息包含 PhoneNumber消息猾蒂,而AddressBook消息包含Person消息均唉。您甚至可以定義嵌套在其他消息中的消息類型 -?? 如您所見, PhoneNumber類型在內部定義Person肚菠。您還可以定義enum舔箭,如果你希望你的領域之一,有預定義的值列表中的一個類型-在這里你要指定一個電話號碼可以是一個MOBILE蚊逢,HOME或 WORK

每個元素上的“= 1”层扶,“= 2”標記標識該字段在二進制編碼中使用的唯一“標記”。

如果未設置字段值时捌, 則使用默認值:數(shù)字類型為零怒医,字符串為空字符串,bools為false奢讨。對于嵌入式消息稚叹,默認值始終是消息的“默認實例”或“原型”,其中沒有設置其字段拿诸。調用訪問器以獲取尚未顯式設置的字段的值始終返回該字段的默認值扒袖。

如果是字段repeated,則字段可以重復任意次數(shù)(包括零)亩码。重復值的順序將保留在協(xié)議緩沖區(qū)中季率。將重復字段視為動態(tài)大小的數(shù)組。

編譯protobuf

下載protoc(windows描沟。下載,把protoc的bin目錄放到環(huán)境變量里飒泻。mac可以使用brew install 去安裝)鞭光。

生成go所需要的pb.go文件需要 go get -u github.com/golang/protobuf/protoc-gen-go。

現(xiàn)在運行編譯器泞遗,指定源目錄(應用程序的源代碼所在的位置 - 如果不提??供值惰许,則使用當前目錄),目標目錄(您希望生成的代碼在哪里;通常同$SRC_DIR) 史辙,以指定你要編譯的.proto汹买。

protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto

輸出go用的文件用go_out,其他語言有其他語言的選項聊倔。

protobuf API

我在我工程的目錄下抄寫了官網(wǎng)代碼晦毙,并在當前目錄下執(zhí)行protoc addressbook.proto --go_out=./

生成的addressbook.pb.go為你提供了下面可用的類型:

  • AddreBook包含了People

  • Person里面有Name,Id,Email,Phones.

  • Person_PhoneNumber包含Number 和Type

  • 類型 Person_PhoneType和Person.PhoneType枚舉

去看下官方示例。

如何創(chuàng)建Person實例

p := pb.Person{
        Id:    1234,
        Name:  "John Doe",
        Email: "jdoe@example.com",
        Phones: []*pb.Person_PhoneNumber{
                {Number: "555-4321", Type: pb.Person_HOME},
        },
}

寫一個消息

使用協(xié)議緩沖區(qū)的全部目的是序列化您的數(shù)據(jù)耙蔑,以便可以在其他地方解析它见妒。在Go中,您使用proto 庫的Marshal 函數(shù)來序列化協(xié)議緩沖區(qū)數(shù)據(jù)纵潦。指向協(xié)議緩沖區(qū)消息的指針struct實現(xiàn)proto.Message 接口徐鹤。調用proto.Marshal返回以其有線格式編碼的protobuf。例如邀层,我們在add_person命令中使用此函數(shù) :

book := &pb.AddressBook{}
// ...

// Write the new address book back to disk.
out, err := proto.Marshal(book)
if err != nil {
        log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fname, out, 0644); err != nil {
        log.Fatalln("Failed to write address book:", err)
}

讀消息

要解析編碼消息返敬,請使用proto庫的 Unmarshal 函數(shù)。調用此方法將數(shù)據(jù)解析buf為協(xié)議緩沖區(qū)并將結果放入pb寥院。因此劲赠,要在list_people命令中解析文件 ,我們使用:

// Read the existing address book.
in, err := ioutil.ReadFile(fname)
if err != nil {
        log.Fatalln("Error reading file:", err)
}
book := &pb.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
        log.Fatalln("Failed to parse address book:", err)
}

擴展protobuf

當你代碼上線之后秸谢,避免不了修改proto文件的定義凛澎。你需要注意一些兼容性規(guī)則。在你的新版本代碼中:

  • 不能更改現(xiàn)有字段的編號估蹄。
  • 可以刪除字段
  • 可以添加字段塑煎,新增字段使用新的編號(從沒用過的,哪怕是給刪除了字段使用過的)

遵循了這些規(guī)則臭蚁,舊代碼在讀消息的時候會忽略你的新代碼最铁。對于刪除的字段,舊代碼也會給其默認值垮兑,刪除的repeated字段將為空冷尉。新代碼也

舊消息中不會出現(xiàn)新字段,因此需要使用默認值執(zhí)行合理操作系枪。使用特定于類型的 默認值 :對于字符串雀哨,默認值為空字符串。對于布爾值,默認值為false雾棺。對于數(shù)字類型膊夹,默認值為零。

示例代碼跑一跑

官方的代碼示例垢村。https://github.com/protocolbuffers/protobuf

首先割疾,我go get下來了。然后用vscode 打開了這個項目嘉栓。

在proto文件目錄下我創(chuàng)建了一個文件夾tutorial(當然文檔里面有個Makefile會幫你做這件事情,但我windows不好使拓诸,手動來)侵佃。以便于生成pb.go文件放入其中(不然 list_people_test.go 里面引入的pb找不到)。

第一例子是以下是list_people命令的單元測試示例 奠支,說明如何創(chuàng)建Person實例:

go test -v list_people_test.go list_people.go(-v是看命令都干了些啥)

寫一條消息(Writing a Message)

go run add_person.go addressbook.data

然后就輸入數(shù)據(jù)寫入到指定的文件中馋辈。

Enter person ID number: 123434
Enter name: mike
Enter email address (blank for none): mike@gmail.com
Enter a phone number (or leave blank to finish): 178933
Is this a mobile, home, or work phone? home
Enter a phone number (or leave blank to finish): 98783
Is this a mobile, home, or work phone? work
Enter a phone number (or leave blank to finish): 123333
Is this a mobile, home, or work phone? mobile

打開addressbook.data,看看內容

"
?mike?{??mike@gmail.com"
?178933
;
?mike??????mike@gmail.com"

?178933??"  
?98783??"
?123333

讀一條消息(Reading a Message)

go run list_people.go addressbook.data

Person ID: 123
  Name: mike
  E-mail address: mike@gmail.com
  Mobile phone #: 178933
Person ID: 123434
  Name: mike
  E-mail address: mike@gmail.com
  Home phone #: 178933
  Work phone #: 98783

我的思考

剝去了絲絲神秘倍谜?就像我當年剛入行讓我給移動端寫接口迈螟,我一頭霧水什么是接口?前輩說ajax寫過吧尔崔。寫過……_

json序列化反序列化知道吧答毫。json改成proto。傳的參數(shù)(類型是Message)是proto文件生成的pb.go文件中的Message季春。也可以看看Message類型是什么洗搂?

type Message interface {
    Reset()
    String() string
    ProtoMessage()
}

只要實現(xiàn)了這三個接口的,就是Message類型了(想想Duck Type)载弄。

我在我工程下耘拇,簡單的練習了下。

p := pb.Person{
    Id:    1234,
    Name:  "Mike",
    Email: "mike@gmail.com",
    Phones: []*pb.Person_PhoneNumber{
        {Number: "555-4321", Type: pb.Person_HOME},
    },
}
book := &pb.AddressBook{
    People: []*pb.Person{&p},
}
out, err := proto.Marshal(book)
if err != nil {
    log.Fatalln("Failed to encode address book:", err)
}
fmt.Println(out)
book1 := &pb.AddressBook{}
proto.Unmarshal(out, book1)
fmt.Printf("%s\n", string(out))
fmt.Printf("%v", book1)

輸出

[10 39 10 4 77 105 107 101 16 210 9 26 14 109 105 107 101 64 103 109 97 105 108 46 99 111 109 34 12 10 8 53 53 53 45 52 51 50 49 16 1]

'
?Mike?? ??mike@gmail.com"
555-4321??
people:<name:"Mike" id:1234 email:"mike@gmail.com" phones:<number:"555-4321" type:HOME > >

參考資料:

《go test 測試用例那些事》https://www.cnblogs.com/li-peng/p/10036468.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宇攻,一起剝皮案震驚了整個濱河市惫叛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逞刷,老刑警劉巖嘉涌,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亲桥,居然都是意外死亡洛心,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門题篷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來词身,“玉大人,你說我怎么就攤上這事番枚》ㄑ希” “怎么了损敷?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長深啤。 經(jīng)常有香客問我拗馒,道長,這世上最難降的妖魔是什么溯街? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任诱桂,我火速辦了婚禮,結果婚禮上呈昔,老公的妹妹穿的比我還像新娘挥等。我一直安慰自己,他們只是感情好堤尾,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布肝劲。 她就那樣靜靜地躺著,像睡著了一般郭宝。 火紅的嫁衣襯著肌膚如雪辞槐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天粘室,我揣著相機與錄音榄檬,去河邊找鬼。 笑死育特,一個胖子當著我的面吹牛丙号,可吹牛的內容都是我干的。 我是一名探鬼主播缰冤,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼犬缨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了棉浸?” 一聲冷哼從身側響起怀薛,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎迷郑,沒想到半個月后枝恋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡嗡害,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年焚碌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霸妹。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡十电,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情鹃骂,我是刑警寧澤台盯,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站畏线,受9級特大地震影響静盅,放射性物質發(fā)生泄漏。R本人自食惡果不足惜寝殴,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一蒿叠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杯矩,春花似錦栈虚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽曼验。三九已至泌射,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鬓照,已是汗流浹背熔酷。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留豺裆,地道東北人拒秘。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像臭猜,于是被迫代替她去往敵國和親躺酒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內容

  • 翻譯查閱外網(wǎng)資料過程中遇到的比較優(yōu)秀的文章和資料蔑歌,一是作為技術參考以便日后查閱羹应,二是訓練英文能力。此文翻譯自 Pr...
    401閱讀 45,107評論 4 30
  • 翻譯查閱外網(wǎng)資料過程中遇到的比較優(yōu)秀的文章和資料次屠,一是作為技術參考以便日后查閱园匹,二是訓練英文能力。此文翻譯自 Pr...
    401閱讀 67,343評論 1 39
  • 去年有段時間得空劫灶,就把谷歌GAE的API權威指南看了一遍裸违,收獲頗豐,特別是在自己幾乎獨立開發(fā)了公司的云數(shù)據(jù)中心之后...
    騎單車的勛爵閱讀 20,475評論 0 41
  • 由于工程項目中擬采用一種簡便高效的數(shù)據(jù)交換格式本昏,百度了一下發(fā)現(xiàn)除了采用 xml供汛、JSON 還有 ProtoBuf(...
    黃海佳閱讀 48,577評論 1 23
  • 聽完貓叔進階版的分享,我結合了自己的經(jīng)歷進行反思發(fā)現(xiàn),強反饋真的很重要紊馏。 2018年11月我開始了我的第一份實習工...
    wxl王小嵐閱讀 254評論 0 1