Golang Gob encoding

gob is a data structure serialization encoding/decoding tool that comes with the Golang package. Use Encoder for encoding and Decoder for decoding. A typical application scenario is RPC (remote procedure calls).

Gob is the same as json's pack and other methods, and the sender uses the Encoder to encode the data structure. After the receiver receives the message, the receiver uses the Decoder to change the serialized data into local variables.

 

One thing to note,

The sender's structure and the receiver's structure do not need to be exactly the same

The default fields in the structure will not be sent. Moreover, on the receiver side, it is not necessary for all fields to have corresponding structural attributes. This example in godoc is pretty figurative:

clip_image001

When the sender passes the value of the struct{A, B int} structure, the receiver can allow the first 9 structures, but the latter 4 structures are indeed not allowed.

 

Personally, I think this setting is very logical: the receiving end only accepts data structures that are " similar " to the data sent. Simulate similarities are allowed, but contradictions are not allowed.

 

Codec rules for each type

Integer: It is divided into sign int and usign int. As can be seen from the above example, int and uint cannot encode and decode each other. float and int are also not mutually encoding and decoding.

Struct, array, slice can be encoded. But functions and channels cannot be encoded.

The bool type is encoded as a uint, 0 is false and 1 is true.

Floating point values ​​are encoded as float64 values

String and []byte transfers are encoded in the form of uint(number of bytes) + byte[]

Slice and array are encoded in the form of uint (number of arrays) + each array code

Maps are encoded in the form of uint(number of Maps) + key-value pairs

 

Struct is encoded in pairs (attribute name + attribute value). The attribute value is its own corresponding gob code. As mentioned earlier, if there is an attribute value of 0 or empty, this attribute is directly ignored. The serial number of each attribute is determined by the sequence of encoding, starting from 0 and increasing sequentially. Struct will use -1 to represent the start of serialization before serialization, and 0 to represent the end of serialization. That is, the serialization of Struct is encoded according to "-1 (0 attribute 1 name attribute 1 value) (1 attribute 2 name attribute 2 value) 0 ".

 

Very important point:

Properties in Struct should be public, that is, they should start with a capital letter.

This can be accessed by functions outside the package! ! (Thanks to TreapDB for the reminder)

Functions provided by Gob

clip_image002

 

Encode和Decode

See this example for Encoder and Decoder:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
)

type P struct {
	X, Y, Z int
	Name    string
}

type Q struct {
	X, Y *int32
	Name string
}

func main() {
	var network bytes.Buffer        
	enc := gob.NewEncoder(&network)
	dec := gob.NewDecoder(&network)
	// Encode (send) the value.
	err := enc.Encode(P{3, 4, 5, "Pythagoras"})
	if err != nil {
		log.Fatal("encode error:", err)
	}
	// Decode (receive) the value.
	var q Q
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error:", err)
	}
	fmt.Println(q)
	fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)

}

All Encoder and Decoder constructors have an io structure, you need to specify which io you will use for encoding and decoding transmission.

There are a few things to note about this code:

1 P and Q are two structures, which should be said to be "similar" two structures

2 Encode is to pass the structure, but the function parameter of Decode is a pointer!

This is stated in godoc:

f e is nil, the value will be discarded. Otherwise, the value underlying e must be a pointer to the correct type for the next data item received.

If the parameter of Decode is not nil, it must be a pointer.

3 If you pass Encode into a pointer, ie

func main() {
	var network bytes.Buffer        // Stand-in for a network connection
	enc := gob.NewEncoder(&network) // Will write to network.
	dec := gob.NewDecoder(&network) // Will read from network.
	// Encode (send) the value.
	err := enc.Encode(&P{3, 4, 5, "Pythagoras"})
	if err != nil {
		log.Fatal("encode error:", err)
	}
	// Decode (receive) the value.
	var q Q
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error:", err)
	}
	fmt.Println(q)
	fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)


}

This function is also no problem.

Register和RegisterName

These two methods need to register the possible types of interface{} when one of the fields in the codec is interface{}. Take a look at the following example:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
)

type P struct {
	X, Y, Z int
	Name    interface{}
}

type Q struct {
	X, Y *int32
	Name interface{}
}

type Inner struct {
	Test int
}

func main() {
	var network bytes.Buffer        // Stand-in for a network connection
	enc := gob.NewEncoder(&network) // Will write to network.
	dec := gob.NewDecoder(&network) // Will read from network.
	
	gob.Register(Inner{})
	
	// Encode (send) the value.
	inner := Inner{1}
	err := enc.Encode(P{1,2,3, inner})
	if err != nil {
		log.Fatal("encode error:", err)
	}
	// Decode (receive) the value.
	var q Q
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error:", err)
	}
	fmt.Println(q)
	fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)


}

Gob.Register(Inner{}) is used here to tell the system that all Interfaces may be Inner structures.

In this example, if you comment gob.Register, the system will report an error.

RegisterName has the same effect as Register, except that Register also attaches an alias to this type.

 

GiveEncoder和GobDecoder

These are two interfaces. If your data structure implements these two interfaces, the corresponding functions of these two structures will be called when encoder.Encode and decoder.Decode are called.

Take a look at the following example:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
)

type P struct {
	X, Y, Z int
	Name    string
}

func (this *P)GobEncode() ([]byte, error) {
    return []byte{},nil
}

type Q struct {
	X, Y *int32
	Name string
}

func main() {
	var network bytes.Buffer        
	enc := gob.NewEncoder(&network)
	dec := gob.NewDecoder(&network)
	// Encode (send) the value.
	err := enc.Encode(P{3, 4, 5, "Pythagoras"})
	if err != nil {
		log.Fatal("encode error:", err)
	}
	// Decode (receive) the value.
	var q Q
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error:", err)
	}
	fmt.Println(q)
	fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)

}

Here my P implements the GobEncoder interface, so func (this *P)GobEncode() ([]byte, error) will be called during enc.Encode

Of course, my function directly returns an empty byte, so I will report an error when decoding: decode error: gob: type mismatch in decoder: want struct type main.Q; got non-struct

These two interfaces are exposed on behalf of you to formulate encoding and decoding rules for the structure you define. Of course, if you use your own codec rules, the process of encoding and decoding needs to be a pair .

postscript

The gob package is a "private" encoding and decoding method provided by golang, and the document also says that it is more efficient than json, xml, etc. (although I have not verified it). Therefore, it is recommended not to use json to communicate with each other between two Go services, and you can directly use gob for data transmission.

References

http://blog.golang.org/2011/03/gobs-of-data.html

http://www.mikespook.com/2011/03/%E3%80%90%E7%BF%BB%E8%AF%91%E3%80%91gob-%E7%9A%84%E6%95%B0%E6%8D%AE/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325470828&siteId=291194637