Protobuf for Go

Protocol buffers are the flexible, efficient, automated solution to solve the problem of serializing and retrieving the structured data. With protocol buffers, you write a .proto description of the data structure you wish to store. From that, the protocol buffer compiler creates a class that implements automatic encoding and parsing of the protocol buffer data with an efficient binary format. Importantly, the protocol buffer format supports the idea of extending the format over time in such a way that the code can still read data encoded with the old format.

How to define the protocol format?

First, to create your address book application, you’ll need to start with a
.proto file.

The .proto file starts with a package declaration, just like this:

syntax = "proto3";
package tutorial;

import "goole/protobuf/timestamp.protp"

we can see that, the format is just like a .go file! It just like Go, the package name is used as the Go package, unless you have specified a go_package

Next, you have your message definitions. Many standard simple data types are available: bool,int32,float,double,string

For example:

message Person {
	string name = 1;
	int32 id = 2;
	string email = 3;
	
	enum PhotoType {
		MOBILE = 0;
		HOME = 1;
		WORK = 2;
	}
	
	message PhonoNumber {
		string number = 1;
		PhotoType type = 2;
	}
	
	repeated PhoneNumber phones = 4;
	
	google.protobuf.Timestamp last_updated = 5;
}
// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}

In the above example, the Person message contains PhoneNumber messages, while the AddressBook message contains Person messages. Also, you can use enum if you want one of your fields to have one of a predefined list of values.

The " = 1", " = 2" markers on each element identify the unique “tag” that field uses in the binary encoding. Normally, we use 1-15 for one less byte to encode. Each element in a repeated field requires re-encoding the tag number, so repeated fields are particularly good candidates for this
optimization.

If a field value isn’t set, a default value is used: zero for numeric types, the empty string for strings, false for bools.

If a field is repeated, the field may be repeated any
number of times (including zero). The order of the repeated values will
be preserved in the protocol buffer. Think of repeated fields as
dynamically sized arrays.

How to user the .proto file?

Now we have a .proto file. But how to use that?

1.we need to install the complier, we can get them from the github

2.run the command

go get -u github.com/golang/protobuf/protoc-gen-go

3.run the compiler, specifying the source directory, the destination directory, and the path to our .proto.we can use the command like this:

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

Because you want Go classes, you use the --go_out option – similar options are provided for other supported languages.

Then, a file named like .pb.go will be created in our destination directory.

The protocol buffer API

From the file we have made. We can get many useful types:

  • An AddressBook structure with a People field.
  • A Person structure with fields for Name,Id, Email and Phones.
  • A Person_PhoneNumber structure, with fields for Number and Type.
  • The type Person_PhoneType and a value defined for each value in the Person.PhoneType enum.

Here is a example of how you might create an instance of Person::

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

Writing a Message

The whole purpose of using protocol buffers is to serialize your data so
that it can be parsed elsewhere.

In Go, you use the proto library’s Marshal function to serialize your protocol buffer data. A pointer to a protocol buffer message’s struct implements the proto.Message interface. Calling proto.Marshal returns the protocol buffer, encoded in its wire format.

For example:

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

// Write the new address book back to disk
out, err := proto.Marshal(bool)
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)
}

Reading a Message

To parse an encoded message, you use the proto library’s Unmarshal function.

For example:

// 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)
}

Extending a protocol buffer

When we write a new .proto from an old .proto, there are some rules we need to follow:

  • must not change the tag numbers of any existing fields.
  • may delete fields.
  • may add new fields but you must use fresh tag numbers.(i.e. tag numbers that were never used in this protocol buffer, not even by deleted fields.)

Reference: https://developers.google.cn/protocol-buffers/docs/gotutorial

发布了16 篇原创文章 · 获赞 0 · 访问量 1315

猜你喜欢

转载自blog.csdn.net/weixin_41036574/article/details/95934814
今日推荐