【Golang語言社群】 Go語言中使用 Protobuf
阿新 • • 發佈:2022-05-04
安裝 goprotobuf
1.從 https://github.com/google/protobuf/releases 獲取 Protobuf 編譯器 protoc(可下載到 Windows 下的二進位制版本
- wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
- tar zxvf protobuf-2.6.1.tar.gz
- cd protobuf-2.6.1
- ./configure
- make
- make install
- protoc -h
複製程式碼
2.獲取 goprotobuf 提供的 Protobuf 編譯器外掛 protoc-gen-go(被放置於 $GOPATH/bin 下,$GOPATH/bin 應該被加入 PATH 環境變數,以便 protoc 能夠找到 protoc-gen-go)
此外掛被 protoc 使用,用於編譯 .proto 檔案為 Golang 原始檔,通過此原始檔可以使用定義在 .proto 檔案中的訊息。
go get github.com/golang/protobuf/protoc-gen-go cd github.com/golang/protobuf/protoc-gen-go go build go install vi /etc/profile 將$GOPATH/bin 加入環境變數 source profile 3.獲取 goprotobuf 提供的支援庫,包含諸如編碼(marshaling)、解碼(unmarshaling)等功能 go get github.com/golang/protobuf/proto cd github.com/golang/protobuf/proto go build go install
複製程式碼
使用 goprotobuf 這裡通過一個例子來說明用法。先建立一個 .proto 檔案 test.proto:
- package example;
- enum FOO { X = 17; };
- message Test {
- required string label = 1;
- optional int32 type = 2 [default=77];
- repeated int64 reps = 3;
- optional group OptionalGroup = 4 {
- required string RequiredField = 5;
- }
- }
複製程式碼
編譯此 .proto 檔案:
- protoc --go_out=. *.proto
複製程式碼
這裡通過 –go_out 來使用 goprotobuf 提供的 Protobuf 編譯器外掛 protoc-gen-go。這時候我們會生成一個名為 test.pb.go 的原始檔。
在使用之前,我們先了解一下每個 Protobuf 訊息在 Golang 中有哪一些可用的介面:
- 每一個 Protobuf 訊息對應一個 Golang 結構體
- 訊息中域名字為 camel_case 在對應的 Golang 結構體中為 CamelCase
- 訊息對應的 Golang 結構體中不存在 setter 方法,只需要直接對結構體賦值即可,賦值時可能使用到一些輔助函式,例如:
複製程式碼
- msg.Foo = proto.String("hello")
- 訊息對應的 Golang 結構體中存在 getter 方法,用於返回域的值,如果域未設定值,則返回一個預設值
- 訊息中非 repeated 的域都被實現為一個指標,指標為 nil 時表示域未設定
- 訊息中 repeated 的域被實現為 slice
- 訪問列舉值時,使用“列舉型別名_列舉名”的格式(更多內容可以直接閱讀生成的原始碼)
- 使用 proto.Marshal 函式進行編碼,使用 proto.Unmarshal 函式進行解碼
- 現在我們編寫一個小程式: 複製程式碼
package main
import (
"log"
// 輔助庫
"github.com/golang/protobuf/proto"
// test.pb.go 的路徑
"example"
)
func main() {
// 建立一個訊息 Test
test := &example.Test{
// 使用輔助函式設定域的值
Label: proto.String("hello"),
Type: proto.Int32(17),
Optionalgroup: &example.Test_OptionalGroup{
RequiredField: proto.String("good bye"),
},
}
// 進行編碼
data, err := proto.Marshal(test)
if err != nil {
log.Fatal("marshaling error: ", err)
}
// 進行解碼
newTest := &example.Test{}
err = proto.Unmarshal(data, newTest)
if err != nil {
log.Fatal("unmarshaling error: ", err)
}
// 測試結果
if test.GetLabel() != newTest.GetLabel() {
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
}
}