1. 程式人生 > 其它 >【Golang語言社群】 Go語言中使用 Protobuf

【Golang語言社群】 Go語言中使用 Protobuf

安裝 goprotobuf

1.從 https://github.com/google/protobuf/releases 獲取 Protobuf 編譯器 protoc(可下載到 Windows 下的二進位制版本

  1. wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
  2. tar zxvf protobuf-2.6.1.tar.gz
  3. cd protobuf-2.6.1
  4. ./configure
  5. make
  6. make install
  7. 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:

  1. package example;
  2. enum FOO { X = 17; };
  3. message Test {
  4. required string label = 1;
  5. optional int32 type = 2 [default=77];
  6. repeated int64 reps = 3;
  7. optional group OptionalGroup = 4 {
  8. required string RequiredField = 5;
  9. }
  10. }

複製程式碼

編譯此 .proto 檔案:

  1. protoc --go_out=. *.proto

複製程式碼

這裡通過 –go_out 來使用 goprotobuf 提供的 Protobuf 編譯器外掛 protoc-gen-go。這時候我們會生成一個名為 test.pb.go 的原始檔。

在使用之前,我們先了解一下每個 Protobuf 訊息在 Golang 中有哪一些可用的介面:

  • 每一個 Protobuf 訊息對應一個 Golang 結構體
  • 訊息中域名字為 camel_case 在對應的 Golang 結構體中為 CamelCase
  • 訊息對應的 Golang 結構體中不存在 setter 方法,只需要直接對結構體賦值即可,賦值時可能使用到一些輔助函式,例如: 複製程式碼
    1. 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())

    }

}