protoBuf-go學習筆記

protoBuf官方簡介

protocol buffers 是一種語言無關、平臺無關、可擴展的序列化結構數據的方法
它可用於(數據)通信協議、數據存儲等。

Protocol Buffers 是一種靈活,高效,自動化機制的結構數據序列化方法
可類比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更爲簡單。

你可以定義數據的結構,然後使用特殊生成的源代碼
輕鬆的在各種數據流中使用各種語言進行編寫和讀取結構數據。
你甚至可以更新數據結構,而不破壞由舊數據結構編譯的已部署程序。

protobuf通過定義包含類型結構序列化信息的文件(.proto文件),來編譯生成不同語言平臺的高效序列化程序代碼

下載protoBuf編譯器

根據不同系統下載不同protoc編譯器,在windows下下載windows後綴的
protoc-3.12.0-rc-1-winxxx.zip

解壓後得到的目錄中,bin目錄中的protoc.exe就是編譯protoc代碼命令

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2020/5/5      1:24                bin
d-----         2020/5/5      1:24                include
-a----         2020/5/5      1:24            724 readme.txt

把protoc.exe複製到GOPATH/bin目錄下

安裝go專屬plugin

protobuf編譯器有支持golang需要安裝protoc-gen-go這個go插件
通過下載源碼編譯後,把編譯出的exe重命名爲protoc-gen-go.exe放到GOPATH/bin下
github.com/golang/protobuf

cd protoc-gen-go
go build main.go

編譯proto到go代碼

在確保有將GOPATH/bin加入環境變量後,即可在任意目錄使用protoc命令

protoc --go_out=.  --proto_path=. *.proto

其中,go_out指定編譯的go代碼輸出路徑,proto_path指定查找proto文件所在的根目錄,最後一個參數是要編譯的proto文件名
最終舊生成了代碼文件xxx.pb.go

proto包名

如果編譯出現警告

Missing 'go_package' option in "test.proto"

這是因爲默認.proto文件中的包聲明生成源代碼時作爲Go的包名,包名中的. 在Go包名中會轉換爲_。
比如proto包名a.b將會變爲Go包名a_b,所以一般通過option go_package指令來指定Go包名
比如如下代碼指定了go包名爲a.b(不管是否定義了proto包名)

option go_package = "a.b";

syntax聲明

一般在proto文件開頭使用syntax聲明proto版本,默認是proto2
比如

syntax = "proto3";

導入包

通過import語句導入proto包,比如

import "google/protobuf/struct.proto"

定義message

protobuf中使用關鍵字message定義結構,並且結構中可以嵌套定義結構,比如

message A {}
message B {
	message C {
	}
}

內嵌類型最終會編譯爲以外部類型名稱_名稱作爲類型名稱的結構體,比如此處,生成的結構體有3個,分別是

type A struct {...}
type B struct {...}
type B_C struct {...}

定義字段

基本定義語法如下,其中type是類型,name是字段名稱,num是數據編號
當反序列化時,會把對應數據編號對應的數據填充到對應字段
對於type,如果是message類型,在編譯爲語言代碼時會被轉化爲對應的指針類型

type  name = num
  • 基本類型
    message A {
    	string name = 1;
    }
    
  • message類型
    message B {
    	string name = 1;
    }
    message A {
    	B b = 1;
    }
    
  • map
    message A {
    	map<string,int> pic = 1;
    }
    
  • 枚舉
    枚舉類型會被編譯爲整型的替代類型,枚舉值會變爲const變量,以類型名_枚舉量名作爲名稱
    與message類似,枚舉也可以嵌套在類型中,最終會編譯爲以外部類型名稱_枚舉名稱作爲類型名稱
    比較獨特的,枚舉枚舉中枚舉量的數值就是他們編譯後代碼中常量的初始化數值,第一個枚舉量的數據編號必須是0
    message A{
      enum Color{
        RED = 0;
        BLACK = 1;
      }
      Color c = 1;
    }
    enum Day{
        ONE = 0;
        TWO = 1;
    }
    
  • repeated類型(數組)
    通過在類型前加上關鍵字repeated代表其爲數組類型,該字段序列化可能出現0次或多次,比如
    message B{}
    message A{
      repeated B bs= 1;
    }
    
    最終生成
    type B struct {...}
    type A struct {
    	...
    	Bs []*B ...
    }
    

定義服務

proto支持通過service與rpc關鍵字分別定義rpc服務和rpc方法,proto默認不會生成rpc代碼,需要結合對應的rpc插件(grpc、twirp等)編譯纔會生成
比如如下代碼,定義了一個service,提供一個search的rpc調用方法,接收一個Request類型的參數,返回Response類型的結果

message Request{}
message Response{}
service Search{
	rpc search(Request) returns(Response);
}

golang使用proto

  • 依賴
    google.golang.org/protobuf/
    
  • 導入包
    google.golang.org/protobuf/proto
    
  • proto.Marshal(interface{} obj) 方法將對象序列化爲字節數組
  • proto.Unmarshal([]byte bs, interface{} obj)方法將字節數組反序列化爲對象
    //A is message
    
    a := A{}
    bis, _ := proto.Marshal(&a)
    
    fmt.Printf("%v\n", bis)
    
    var r A
    proto.Unmarshal(bis, &r)
    
    fmt.Printf("%v\n", r)
    

歡迎找歪歪梯聊騷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章