©
本文档使用
php.cn手册 发布
import "encoding/gob"
Overview
Index
Examples
Package gob管理gobs流 - 在编码器(发送器)和解码器(接收器)之间交换的二进制值。一个典型的用途是传输远程过程调用(RPC)的参数和结果,如由“net / rpc”包提供的那些。
该实现为流中的每种数据类型编译自定义编解码器,并且在使用单个编码器传输值流时缓解编译成本,效率最高。
gob是自我描述的。流中的每个数据项都有一个类型的规范,用一组预定义的类型表示。指针不传输,但它们指向的内容被传送; 也就是说,这些值是平坦的。无指针是不允许的,因为它们没有价值。递归类型工作正常,但递归值(带周期的数据)是有问题的。这可能会改变。
要使用gobs,请创建一个编码器,并将其与一系列数据项一起呈现为值或地址,这些值可以取消引用值。编码器确保在需要之前发送所有类型的信息。在接收端,解码器从编码流中检索值并将它们解压缩成局部变量。
源和目标值/类型不需要完全对应。对于结构体来说,源中但没有接收变量的域(由名称标识)将被忽略。在接收变量中但从传输类型或值中缺失的字段将在目标中被忽略。如果同时存在两个同名的字段,则其类型必须兼容。接收器和发射器都将执行所有必要的间接和取消引用,以在gob和实际Go值之间进行转换。例如,示意性的采空区类型,
struct { A, B int }
可以从以下任何一种Go类型发送或接收:
struct { A, B int }// the same*struct { A, B int }// extra indirection of the structstruct { *A, **B int }// extra indirection of the fieldsstruct { A, B int64 }// different concrete value type; see below
它也可以被接收到以下任何一个中:
struct { A, B int }// the samestruct { B, A int }// ordering doesn't matter; matching is by namestruct { A, B, C int }// extra field (C) ignoredstruct { B int }// missing field (A) ignored; data will be droppedstruct { B, C int }// missing field (A) ignored; extra field (C) ignored.
尝试接收这些类型将导致解码错误:
struct { A int; B uint }// change of signedness for Bstruct { A int; B float }// change of type for Bstruct { }// no field names in commonstruct { C, D int }// no field names in common
整数以两种方式传输:任意精度有符号整数或任意精度无符号整数。gob格式中没有int8,int16等歧视; 只有有符号和无符号的整数。如下所述,发送器以可变长度编码发送值; 接收器接受该值并将其存储在目标变量中。浮点数总是使用IEEE-754 64位精度发送(见下文)。
带符号的整数可以接收到任何有符号的整数变量中:int,int16等; 无符号整数可以接收到任何无符号整数变量中; 并且可以将浮点值接收到任何浮点变量中。但是,目标变量必须能够表示值,否则解码操作将失败。
结构,数组和片也被支持。结构仅对导出的字段进行编码和解码。字符串和字节数组以特殊的高效表示形式提供支持(请参见下文)。当一个片段被解码时,如果现有片段具有容量,片段将被扩展到位; 如果不是,则分配一个新数组。无论如何,结果切片的长度报告解码的元素的数量。
通常,如果需要分配,解码器将分配内存。如果不是,它将使用从流中读取的值更新目标变量。它不会首先初始化它们,因此如果目标是复合值(如地图,结构或切片),则解码值将按照元素方式合并到现有变量中。
功能和频道不会以采空区发送。试图在顶层编码这样的值将会失败。chan或func类型的struct字段被视为完全像未导出的字段,并被忽略。
Gob可以按照优先顺序调用相应的方法来编码实现GobEncoder或encoding.BinaryMarshaler接口的任何类型的值。
Gob可以通过调用相应的方法来解码实现GobDecoder或编码的任何类型的值.BinaryUnmarshaler接口也会按照该优先顺序再次进行解码。
本节介绍编码,对大多数用户不重要的详细信息。细节从下到上呈现。
无符号整数以两种方式之一发送。如果它小于128,则将其作为具有该值的字节发送。否则,它将作为保留该值的最小长度的大端(高字节的第一个)字节流发送,前面是一个保存字节计数的字节,取反。因此,0发送为,7发送为(07),256发送为 (FE 01 00)。
布尔值在无符号整数内编码:0代表假,1代表真。
一个有符号整数i被编码在一个无符号整数u中。在u中,位1向上包含该值; 位0表示它们是否应该在收到时补充。编码算法如下所示:
var u uintif i < 0 { u = (^uint(i) << 1) | 1 // 补充 i, 位0是1} else { u = (uint(i) << 1) // 不补充 i, 位0是0}encodeUnsigned(u)
低位因此类似于符号位,但是使其成为补码位而不是保证最大的负整数不是特例。例如,-129=^128=(^256>>1)编码为(FE 01 01)。
浮点数字总是作为float64值的表示形式发送。该值使用math.Float64bits转换为uint64。uint64然后被字节反转并作为常规无符号整数发送。字节反转意味着尾数的指数和高精度部分先行。由于低位通常为零,因此可以节省编码字节。例如,17.0只用三个字节编码 (FE 31 40)。
字符串和字节片段作为无符号计数发送,然后是该值的许多未解释的字节。
所有其他切片和数组都作为无符号计数发送,然后递归地使用标准采样编码作为其类型。
地图是作为无符号计数发送的,然后是许多键元素对。空的但非零的地图被发送,所以如果接收方还没有分配一个地图,则一直会在接收时分配一个地图,除非传输的地图是零而不是在顶层。
在切片和阵列以及地图中,即使所有元素均为零,也会传输所有元素,即使是零值元素。
结构以(字段号,字段值)对的序列发送。字段值是使用递归的类型的标准gob编码发送的。如果某个字段的类型为零(数组除外;请参见上文),则该字段在传输中将被忽略。字段编号由编码结构的类型定义:编码类型的第一个字段是字段0,第二个字段是字段1等。编码值时,字段编号为delta编码以提高效率,字段始终按照增加字段的顺序发送; 三角洲因此没有签名。增量编码的初始化将字段编号设置为-1,因此具有值7的无符号整数字段0作为无符号的增量= 1,无符号的值= 7或(01 07)发送。最后,在所有字段发送之后,终止标记表示结构的结束。
接口类型不检查兼容性; 所有接口类型都作为单个“接口”类型的成员进行处理,类似于int或[] byte - 实际上它们都被视为interface {}。接口值以字符串的形式传输,标识发送的具体类型(必须通过调用寄存器预先定义的名称),然后是以下数据长度的字节数(因此,如果不能存储),然后是存储在接口值中的具体(动态)值的通常编码。(一个零接口值由空字符串标识并且不传送任何值。)一旦收到,解码器就会验证解包后的具体项目是否满足接收变量的接口。
如果一个值传递给Encode,并且该类型不是一个结构体(或指向结构体的指针等),为了简化处理,它被表示为一个字段的结构。这样做的唯一可见效果是在值之后编码一个零字节,就像编码结构的最后一个字段之后一样,以便解码算法知道顶级值何时完成。
类型的表示如下所述。当在编码器和解码器之间的给定连接上定义类型时,它被分配一个有符号的整数类型ID。当调用Encoder.Encode(v)时,它确保为v及其所有元素的类型分配一个id,然后发送该对 (typeid, encoded-v),其中typeid是编码类型的类型id v和encoded-v是值v的gob编码。
为了定义一个类型,编码器选择一个未使用的肯定类型id,并发送这个对(-type id, encoded-type),其中encoded-type是wireType描述的gob编码,由以下类型构造而成:
type wireType struct { ArrayT *ArrayType SliceT *SliceType StructT *StructType MapT *MapType}type arrayType struct { CommonType Elem typeId Len int}type CommonType struct { Name string // the name of the struct type Id int // the id of the type, repeated so it's inside the type}type sliceType struct { CommonType Elem typeId}type structType struct { CommonType Field []*fieldType // the fields of the struct.}type fieldType struct { Name string // the name of the field. Id int // the type id of the field, which must be already defined}type mapType struct { CommonType Key typeId Elem typeId}
如果存在嵌套类型标识,则必须在使用顶级类型标识描述encoded-v之前定义所有内部类型标识的类型。
为了简化设置,连接被定义为先验地理解这些类型,以及基本采样类型int,uint等。它们的ID是:
bool 1int 2uint 3float 4[]byte 5string 6complex 7interface 8// gap for reserved ids.WireType 16ArrayType 17CommonType 18SliceType 19StructType 20FieldType 21// 22 is slice of fieldType.MapType 23
最后,通过对Encode的调用创建的每条消息前面都有一个编码的无符号整数数量,该数量是消息中剩余的字节数。在初始类型名称之后,接口值以相同方式包装; 实际上,接口值的作用类似于Encode的递归调用。
总之,一个gob流看起来像
(byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
其中*表示重复次数为零或更多,并且值的类型ID必须预先定义或在流中的值之前定义。
兼容性:对软件包的未来更改将尽力保持与使用先前版本编码的流的兼容性。也就是说,这个软件包的任何发布版本都应该能够解码使用任何以前发布的版本编写的数据,并受到诸如安全修复等问题的影响。有关背景信息,请参阅Go兼容性文档:https://golang.org/doc/go1compat
关于gob线格式的设计讨论,请参阅“数据采集”:https://blog.golang.org/gobs-of-data
这个例子显示了软件包的基本用法:创建一个编码器,传输一些值,用解码器接收它们。
package mainimport ("bytes""encoding/gob""fmt""log")type P struct { X, Y, Z int Name string}type Q struct { X, Y *int32 Name string}// This example shows the basic usage of the package: Create an encoder,// transmit some values, receive them with a decoder.func main() {// Initialize the encoder and decoder. Normally enc and dec would be// bound to network connections and the encoder and decoder would// run in different processes.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) some values. err := enc.Encode(P{3, 4, 5, "Pythagoras"})if err != nil { log.Fatal("encode error:", err)} err = enc.Encode(P{1782, 1841, 1922, "Treehouse"})if err != nil { log.Fatal("encode error:", err)}// Decode (receive) and print the values.var q Q err = dec.Decode(&q)if err != nil { log.Fatal("decode error 1:", err)} fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y) err = dec.Decode(&q)if err != nil { log.Fatal("decode error 2:", err)} fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)}
本示例传输一个实现自定义编码和解码方法的值。
package mainimport ("bytes""encoding/gob""fmt""log")// The Vector type has unexported fields, which the package cannot access.// We therefore write a BinaryMarshal/BinaryUnmarshal method pair to allow us// to send and receive the type with the gob package. These interfaces are// defined in the "encoding" package.// We could equivalently use the locally defined GobEncode/GobDecoder// interfaces.type Vector struct { x, y, z int}func (v Vector) MarshalBinary() ([]byte, error) {// A simple encoding: plain text.var b bytes.Buffer fmt.Fprintln(&b, v.x, v.y, v.z)return b.Bytes(), nil}// UnmarshalBinary modifies the receiver so it must take a pointer receiver.func (v *Vector) UnmarshalBinary(data []byte) error {// A simple encoding: plain text. b := bytes.NewBuffer(data) _, err := fmt.Fscanln(b, &v.x, &v.y, &v.z)return err}// This example transmits a value that implements the custom encoding and decoding methods.func main() {var network bytes.Buffer // Stand-in for the network.// Create an encoder and send a value. enc := gob.NewEncoder(&network) err := enc.Encode(Vector{3, 4, 5})if err != nil { log.Fatal("encode:", err)}// Create a decoder and receive a value. dec := gob.NewDecoder(&network)var v Vector err = dec.Decode(&v)if err != nil { log.Fatal("decode:", err)} fmt.Println(v)}
此示例显示如何对接口值进行编码。与常规类型的主要区别在于注册实现接口的具体类型。
package mainimport ("bytes""encoding/gob""fmt""log""math")type Point struct { X, Y int}func (p Point) Hypotenuse() float64 {return math.Hypot(float64(p.X), float64(p.Y))}type Pythagoras interface {Hypotenuse() float64}// This example shows how to encode an interface value. The key// distinction from regular types is to register the concrete type that// implements the interface.func main() {var network bytes.Buffer // Stand-in for the network.// We must register the concrete type for the encoder and decoder (which would// normally be on a separate machine from the encoder). On each end, this tells the// engine which concrete type is being sent that implements the interface. gob.Register(Point{})// Create an encoder and send some values. enc := gob.NewEncoder(&network)for i := 1; i <= 3; i++ {interfaceEncode(enc, Point{3 * i, 4 * i})}// Create a decoder and receive some values. dec := gob.NewDecoder(&network)for i := 1; i <= 3; i++ { result := interfaceDecode(dec) fmt.Println(result.Hypotenuse())}}// interfaceEncode encodes the interface value into the encoder.func interfaceEncode(enc *gob.Encoder, p Pythagoras) {// The encode will fail unless the concrete type has been// registered. We registered it in the calling function.// Pass pointer to interface so Encode sees (and hence sends) a value of// interface type. If we passed p directly it would see the concrete type instead.// See the blog post, "The Laws of Reflection" for background. err := enc.Encode(&p)if err != nil { log.Fatal("encode:", err)}}// interfaceDecode decodes the next interface value from the stream and returns it.func interfaceDecode(dec *gob.Decoder) Pythagoras {// The decode will fail unless the concrete type on the wire has been// registered. We registered it in the calling function.var p Pythagoras err := dec.Decode(&p)if err != nil { log.Fatal("decode:", err)}return p}
func Register(value interface{})
func RegisterName(name string, value interface{})
type CommonType
type Decoder
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(e interface{}) error
func (dec *Decoder) DecodeValue(v reflect.Value) error
type Encoder
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(e interface{}) error
func (enc *Encoder) EncodeValue(value reflect.Value) error
type GobDecoder
type GobEncoder
Package (Basic) Package (EncodeDecode) Package (Interface)
dec_helpers.go decode.go decoder.go doc.go enc_helpers.go encode.go encoder.go error.go type.go
func Register(value interface{})
在其内部类型名称下注册记录类型,由该类型的值标识。该名称将标识作为接口变量发送或接收的值的具体类型。只需要注册将作为接口值实现传输的类型。期望仅在初始化期间使用,如果类型和名称之间的映射不是双向映射,则会发生混乱。
func RegisterName(name string, value interface{})
RegisterName与Register类似,但使用提供的名称而不是类型的默认值。
CommonType保存所有类型的元素。它是一个历史工件,保存为二进制兼容性,并且仅为了包类型描述符的编码而导出。它不适合客户直接使用。
type CommonType struct { Name string Id typeId}
解码器管理从连接的远程端读取的类型和数据信息的接收。
解码器只对解码输入大小进行基本的理智检查,并且其限制是不可配置的。解码来自不受信任来源的gob数据时请小心。
type Decoder struct { // contains filtered or unexported fields}
func NewDecoder(r io.Reader) *Decoder
NewDecoder返回一个从io.Reader读取的新解码器。如果r不实现io.ByteReader,它将被包装在一个bufio.Reader中。
func (dec *Decoder) Decode(e interface{}) error
解码从输入流中读取下一个值并将其存储在由空接口值表示的数据中。如果e为零,则该值将被丢弃。否则,e下面的值必须是指向下一个接收数据项的正确类型的指针。如果输入是在EOF,解码返回io.EOF并且不修改e。
func (dec *Decoder) DecodeValue(v reflect.Value) error
DecodeValue从输入流中读取下一个值。如果v是zero reflect.Value(v.Kind()==无效),则DecodeValue丢弃该值。否则,它将值存储到v中。在这种情况下,v必须表示一个非零指向数据的指针,或者是可赋值的reflect.Value(v.CanSet())如果输入位于EOF,DecodeValue返回io.EOF,不修改v。
编码器管理类型和数据信息传输到连接的另一端。
type Encoder struct { // contains filtered or unexported fields}
func NewEncoder(w io.Writer) *Encoder
NewEncoder返回一个将在io.Writer上传输的新编码器。
func (enc *Encoder) Encode(e interface{}) error
编码传输由空接口值表示的数据项,保证所有必需的类型信息先传送。传递一个零指针给编码器会惊慌,因为它们不能通过gob传输。
func (enc *Encoder) EncodeValue(value reflect.Value) error
EncodeValue传输由反射值表示的数据项,保证所有必要的类型信息都先传输完毕。将一个零指针传递给EncodeValue将会发生混乱,因为它们不能通过gob进行传输。
GobDecoder是描述数据的接口,它提供自己的例程来解码由GobEncoder发送的传输值。
type GobDecoder interface { // GobDecode overwrites the receiver, which must be a pointer, // with the value represented by the byte slice, which was written // by GobEncode, usually for the same concrete type. GobDecode([]byte) error}
GobEncoder是描述数据的接口,它为编码值提供了自己的表示,以便传输给GobDecoder。实现GobEncoder和GobDecoder的类型可以完全控制其数据的表示,因此可能包含私有字段,通道和函数,这些通常不会在gob流中传输。
注意:由于gobs可以永久保存,因此确保GobEncoder使用的编码在软件变化时保持稳定是一个很好的设计。例如,GobEncode在编码中包含一个版本号可能是有意义的。
type GobEncoder interface { // GobEncode returns a byte slice representing the encoding of the // receiver for transmission to a GobDecoder, usually of the same // concrete type. GobEncode() ([]byte, error)}