這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
如果你對Google Protocol Buffer不瞭解,可以先看下我這篇文章裡收集的中文資料:關於Google Protocol Buffer的中文資料
源碼地址:https://code.google.com/p/goprotobuf/
詳細的介紹:https://code.google.com/p/goprotobuf/source/browse/README
介紹:
This software has two parts: a ‘protocol compiler plugin’ that generates Go source files that, once compiled, can access and manage protocol buffers; and a library that implements run-time support for encoding (marshaling), decoding (unmarshaling), and accessing protocol buffers.
大意:
該軟體包含兩部分:protoc-gen-go:一旦使用’協議編譯器外掛程式‘編譯,會產生一些go的源碼檔案,可以訪問和管理protocol buffers;proto:是一個實現運行時支援,為編碼(編組),解碼(解編)的庫,和訪問protocol buffers。
簡單的說,protoc-gen-go是一個編譯器,用來把 *.proto協議檔案,編譯產生 *.pb.go檔案。再接下來的例子,我們會介紹如何使用它。
而proto需要包含到我們的軟體裡,去將訊息編碼為位元據,或者將位元據還原為訊息對象。
源碼下載:
go get -u code.google.com/p/goprotobuf/{proto,protoc-gen-go}
或者直接下載源碼到自己的項目裡:
hg clone https://code.google.com/p/goprotobuf/
如:
編譯:
編譯成功後,我們會發現bin目錄下,會產生protoc-gen-go檔案,以及pkg目錄下會產生對應的庫檔案。
接下來,我們編寫測試一個例子:
首先,編寫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;
}
}
接著,編寫Makefile檔案,用於產生*.pb.go檔案,內容如下:
include ../code.google.com/p/goprotobuf/Make.protobuf
all:regenerate
regenerate:
rm -f test.pb.go
make test.pb.go
# The following rules are just aids to development. Not needed for typical testing.
diff:regenerate
hg diff test.pb.go
restore:
cp test.pb.go.golden test.pb.go
preserve:
cp test.pb.go test.pb.go.golden
終端下,make以後,我們會看到產生對應的test.pb.go檔案,內容如下:
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
package example
import proto "code.google.com/p/goprotobuf/proto"
import json "encoding/json"
import math "math"
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
type FOO int32
const (
FOO_X FOO = 17
)
var FOO_name = map[int32]string{
17: "X",
}
var FOO_value = map[string]int32{
"X": 17,
}
func (x FOO) Enum() *FOO {
p := new(FOO)
*p = x
return p
}
func (x FOO) String() string {
return proto.EnumName(FOO_name, int32(x))
}
func (x FOO) MarshalJSON() ([]byte, error) {
return json.Marshal(x.String())
}
func (x *FOO) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
if err != nil {
return err
}
*x = FOO(value)
return nil
}
type Test struct {
Label *string protobuf:"bytes,1,req,name=label" json:"label,omitempty"
Type *int32 protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"
Reps []int64 protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"
Optionalgroup *Test_OptionalGroup protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"
XXX_unrecognized []byte json:"-"
}
func (this *Test) Reset() { *this = Test{} }
func (this *Test) String() string { return proto.CompactTextString(this) }
func (*Test) ProtoMessage() {}
const Default_Test_Type int32 = 77
func (this *Test) GetLabel() string {
if this != nil && this.Label != nil {
return *this.Label
}
return ""
}
func (this *Test) GetType() int32 {
if this != nil && this.Type != nil {
return *this.Type
}
return Default_Test_Type
}
func (this *Test) GetOptionalgroup() *Test_OptionalGroup {
if this != nil {
return this.Optionalgroup
}
return nil
}
type Test_OptionalGroup struct {
RequiredField *string protobuf:"bytes,5,req" json:"RequiredField,omitempty"
}
func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} }
func (this *Test_OptionalGroup) GetRequiredField() string {
if this != nil && this.RequiredField != nil {
return *this.RequiredField
}
return ""
}
func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
}
最後,編寫測試代碼如下:
package main
import (
"log"
"code.google.com/p/goprotobuf/proto"
"example"
"fmt"
)
func main() {
test := &example.Test{
Label: proto.String("hello"),
Type: proto.Int32(17),
Optionalgroup: &example.Test_OptionalGroup{
RequiredField: proto.String("good bye"),
},
}
// print test by string.
fmt.Println(test.String())
data, err := proto.Marshal(test)
if err != nil {
log.Fatal("marshaling error: ", err)
}
// print data
fmt.Println(data)
newTest := &example.Test{}
err = proto.Unmarshal(data, newTest)
if err != nil {
log.Fatal("unmarshaling error: ", err)
}
// Now test and newTest contain the same data.
if test.GetLabel() != newTest.GetLabel() {
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
}
// etc.
}
編譯運行,結果如下:
這裡只是簡單介紹並編寫了個測試例子,許多細節並沒有介紹,以後有機會再跟大家分享。