# package gob
`import "encoding/gob"`
gob包管理gob流——在編碼器(發送器)和解碼器(接受器)之間交換的binary值。一般用于傳遞遠端程序調用(RPC)的參數和結果,如net/rpc包就有提供。
本實現給每一個數據類型都編譯生成一個編解碼程序,當單個編碼器用于傳遞數據流時,會分期償還編譯的消耗,是效率最高的。
### Basics
Gob流是自解碼的。流中的所有數據都有前綴(采用一個預定義類型的集合)指明其類型。指針不會傳遞,而是傳遞值;也就是說數據是壓平了的。遞歸的類型可以很好的工作,但是遞歸的值(比如說值內某個成員直接/間接指向該值)會出問題。這個問題將來可能會修復。
要使用gob,先要創建一個編碼器,并向其一共一系列數據:可以是值,也可以是指向實際存在數據的指針。編碼器會確保所有必要的類型信息都被發送。在接收端,解碼器從編碼數據流中恢復數據并將它們填寫進本地變量里。
### Types and Values
發送端和接收端的值/類型不需要嚴格匹配。對結構體來說,字段(根據字段名識別)如果發送端有而接收端沒有,會被忽略;接收端有而發送端沒有的字段也會被忽略;發送端和接收端都有的字段其類型必須是可兼容的;發送端和接收端都會在gob流和實際go類型之間進行必要的指針取址/尋址工作。舉例如下:
```
struct { A, B int }
```
可以和如下類型互相發送和接收:
```
struct { A, B int } // 同一類型
*struct { A, B int } // 結構體需要額外重定向(指針)
struct { *A, **B int } // 字段需要額外重定向(指針)
struct { A, B int64 } // 同為整型/浮點型且符號類型相同的不同值類型,參見下面
```
可以發送給如下任一類型:
```
struct { A, B int } // 同一類型
struct { B, A int } // 字段順序改變無影響,按名稱匹配
struct { A, B, C int } // 忽略多出的字段C
struct { B int } // 忽略缺少的字段A,會丟棄A的值
struct { B, C int } // 忽略缺少的字段A,忽略多出的字段C
```
但嘗試發送給如下類型的話就會導致錯誤:
```
struct { A int; B uint } // B字段改變了符號類型
struct { A int; B float } // B字段改變了類型
struct { } // 無共同字段名
struct { C, D int } // 無共同字段名
```
整數以兩種方式傳遞:任意精度有符號整數和任意精度無符號整數。Gob里只有無符號和有符號整數的區別,沒有int8、int16等類型的區分。如下所述,發送端會以變長編碼發送整數值;接收端接收整數并保存在目標變量里。浮點數則總是使用IEEE-754 64位精度(參見下述)。
有符號整數可以被任意有符號整形接收:int、int16等;無符號整數可以被任意無符號整形接收;浮點數可以被任意浮點數類型接收。但是,接收端類型必須能容納該值(上溢/下溢都不行),否則解碼操作會失敗。
結構體、數組和切片都被支持。結構體只編碼和解碼導出字段。字符串和byte數組/切片有專門的高效表示(參見下述)。當解碼切片時,如果當前切片的容量足夠會被復用,否則會申請新的底層數組(所以還是用切片地址為好)。此外,生成的切片的長度會修改為解碼的成員的個數。
Gob流不支持函數和通道。試圖在最頂層編碼這些類型的值會導致失敗。結構體中包含函數或者通道類型的字段的話,會視作非導出字段(忽略)處理。
Gob可以編碼任意實現了GobEncoder接口或者encoding.BinaryMarshaler接口的類型的值(通過調用對應的方法),GobEncoder接口優先。
Gob可以解碼任意實現了GobDecoder接口或者encoding.BinaryUnmarshaler接口的類型的值(通過調用對應的方法),同樣GobDecoder接口優先。
### Encoding Details
這部分文檔是編碼細節,對多數使用者并不重要。細節是按從底向上的順序展示的。
無符號整數用兩種方法發送。如果該整數小于128,則以一個字節發送該值;否則采用最小長度大端在前的字節流保存該整數,并在最前面使用一個字節保存字節流的字節數相反數。因此0被發送為(00),7被發送為(07),而256被發送為(FE 01 00)(字節數2,其相反數-2,用補碼表示,為FE)。
布爾值按無符號整數編碼,0表示假,1表示真。
有符號整數翻譯為一個無符號整數(i=>u)來編碼。u的最低字位表示值的符號(以及是否應對值按位取反);其余位表示值。編碼算法表示為如下(非實際代碼):
```
uint u;
if i < 0 {
u = (^i << 1) | 1 // i按位取反,左移1位,第1位設為1
} else {
u = (i << 1) // i不進行取反,左移1位,第1位為0
}
encodeUnsigned(u)
```
這樣一來,最低位就相當于標志位,但還會對負數按位取反,以便保證負數不會出現特殊情況(補碼表示的負數,其表示會受到整數類型的影響)。如,-129=^128=(^256>>1)編碼為(FE 01 01)。
浮點數的數值,首先總是轉換float64類型值,該值使用math.Float64bits?函數轉換為一個uint64整數,然后將字節序顛倒過來,最后作為一個普通無符號數編碼傳輸。顛倒字節序說明數字的指數和高精度位數部分首先傳送。因為低位一般是0,這樣可以節約編碼的字節數。例如,17.0編碼后只有三個字節(FE 31 40)。
字符串和byte數組/切片發送為一個無符號整數指定的字節數后跟不作處理的字節序列。
其它切片和數組都發送為一個無符號整數指定的成員個數后跟所有成員的遞歸表示的gob編碼。
映射發送為一個無符號整數指定的鍵值對數后給許多鍵和值的gob編碼。非nil但無成員的映射也會發送,因此如果發送者申請了一個映射,接收方也會申請一個映射,即使該映射內沒有元素。
結構體也以鍵值對(字段名:字段值)序列的形式發送。字段值采用遞歸表示的gob編碼發送。如果字段為其類型的零值,則該字段不會被發送。字段編號由編碼的結構體的類型確定:編碼類型的第一個字段為字段0,第二個為字段1,依次類推。當編碼一個結構體的值時,字段編號出于效率考慮是增量編碼的,字段總是按字段編號遞增的順序被編碼,增量是無符號整數。增量編碼將字段編號初始化為-1,因此無符號整型值為7的字段0編碼為增量1值7。最后,所有的字段都被發送后,會發送終止標記表明結構體的結束。終止標記為一個增量為0的值,其表示為(00)。
接口類型不會檢查兼容性;所有的接口都被視為同一種“接口”類型來傳輸;類似整數和字節切片,它們都被視為interface{}類型。接口值發送為一個表示其具體類型的字符串標志符(必須由調用者預先注冊的名稱)后跟表示后續數據字節數的無符號整數(以便需要時可以跳過該值),再后跟保存在接口里的值的動態具體類型的gob編碼。nil接口值會發送為標志符為空字符串、不發送值的接口。在接收到之后,由解碼器驗證該值是否滿足接收端變量接口。
類型的表示如下所示。當一個編碼器和解碼器的連接中定義了一個類型時,該類型會被指定一個整數類型ID。當調用Encoder.Encode(v)時,該方法會確保v及v所有成員都有對應ID,然后本方法會發送一系列對(typeid,encoded-v)?,其中typeid是編碼類型的類型ID,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 // 結構體的名字
Id int // 類型的ID
}
type sliceType struct {
CommonType
Elem typeId
}
type structType struct {
CommonType
Field []*fieldType // 結構體的字段
}
type fieldType struct {
Name string // 字段名
Id int // 字段的類型ID,必須是已經定義的類型
}
type mapType struct {
CommonType
Key typeId
Elem typeId
}
```
如果有嵌套的類型,必須先定義所有內部類型的ID才能定義頂層類型的ID用于描述encoded-v。
為了簡化啟動,有些類型是預先定義好了的,這些類型及其ID如下:
```
bool 1
int 2
uint 3
float 4
[]byte 5
string 6
complex 7
interface 8
// 空缺用于保留ID
WireType 16
ArrayType 17
CommonType 18
SliceType 19
StructType 20
FieldType 21
// 22是[]fieldType類型的ID
MapType 23
```
最后,每一次調用Encode創建的信息都會以一個編碼了的無符號整數指明消息剩余部分的字節數。在開始的類型名后面,接口值也以同樣的方式包裝;事實上,接口值表現的就像對Encode進行遞歸調用一樣。
總的來說,一個gob流看起來是這樣的:
```
(byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
```
其中*表示0或多次重復,值的類型id必須是預定義的,或者在流中值的前面定義。
參見"Gobs of data"獲取gob wire格式的設計討論:
[http://golang.org/doc/articles/gobs_of_data.html](http://golang.org/doc/articles/gobs_of_data.html)
Example (Basic)
```
package gob_test
import (
"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 Example_basic() {
// 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)
// Output:
// "Pythagoras": {3, 4}
// "Treehouse": {1782, 1841}
}
```
Example (EncodeDecode)
```
package gob_test
import (
"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 Example_encodeDecode() {
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)
// Output:
// {3 4 5}
}
```
Example (Interface)
```
package gob_test
import (
"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 Example_interface() {
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())
}
// Output:
// 5
// 10
// 15
}
// 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
}
```
## Index
* [type GobDecoder](#GobDecoder)
* [type GobEncoder](#GobEncoder)
* [func Register(value interface{})](#Register)
* [func RegisterName(name string, value interface{})](#RegisterName)
* [type Decoder](#Decoder)
* [func NewDecoder(r io.Reader) *Decoder](#NewDecoder)
* [func (dec *Decoder) Decode(e interface{}) error](#Decoder.Decode)
* [func (dec *Decoder) DecodeValue(v reflect.Value) error](#Decoder.DecodeValue)
* [type Encoder](#Encoder)
* [func NewEncoder(w io.Writer) *Encoder](#NewEncoder)
* [func (enc *Encoder) Encode(e interface{}) error](#Encoder.Encode)
* [func (enc *Encoder) EncodeValue(value reflect.Value) error](#Encoder.EncodeValue)
* [type CommonType](#CommonType)
### Examples
* [package (Basic)](#example-package--Basic)
* [package (EncodeDecode)](#example-package--EncodeDecode)
* [package (Interface)](#example-package--Interface)
## type [GobDecoder](https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L773 "View Source")
```
type GobDecoder interface {
// GobDecode必須是指針的方法,使用切片數據重寫指針指向的值
// 切片數據應該由同一具體類型的GobEncode生成
GobDecode([]byte) error
}
```
GobDecoder是一個描述數據的接口,提供自己的方案來解碼GobEncoder發送的數據。
## type [GobEncoder](https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L764 "View Source")
```
type GobEncoder interface {
// GobEncode方法返回一個代表值的切片數據
// 該切片數據由同一類型的指針方法GobDecoder接受解碼
GobEncode() ([]byte, error)
}
```
GobEncoder是一個描述數據的接口,提供自己的方案來將數據編碼供GobDecoder接收并解碼。一個實現了GobEncoder接口和GobDecoder接口的類型可以完全控制自身數據的表示,因此可以包含非導出字段、通道、函數等數據,這些數據gob流正常是不能傳輸的。
注意:因為gob數據可以被永久保存,在軟件更新的過程中保證用于GobEncoder編碼的數據的穩定性(保證兼容)是較好的設計原則。例如,讓GobEncode?接口在編碼后數據里包含版本信息可能很有意義。
## func [Register](https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L816 "View Source")
```
func Register(value interface{})
```
Register記錄value下層具體值的類型和其名稱。該名稱將用來識別發送或接受接口類型值時下層的具體類型。本函數只應在初始化時調用,如果類型和名字的映射不是一一對應的,會panic。
## func [RegisterName](https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L788 "View Source")
```
func RegisterName(name string, value interface{})
```
RegisterName類似Register,淡灰使用提供的name代替類型的默認名稱。
## type [Decoder](https://github.com/golang/go/blob/master/src/encoding/gob/decoder.go#L18 "View Source")
```
type Decoder struct {
// 內含隱藏或不導出字段
}
```
Decoder管理從連接遠端讀取的類型和數據信息的解釋(的操作)。
### func [NewDecoder](https://github.com/golang/go/blob/master/src/encoding/gob/decoder.go#L34 "View Source")
```
func NewDecoder(r io.Reader) *Decoder
```
函數返回一個從r讀取數據的\*Decoder,如果r不滿足io.ByteReader接口,則會包裝r為bufio.Reader。
### func (\*Decoder) [Decode](https://github.com/golang/go/blob/master/src/encoding/gob/decoder.go#L193 "View Source")
```
func (dec *Decoder) Decode(e interface{}) error
```
Decode從輸入流讀取下一個之并將該值存入e。如果e是nil,將丟棄該值;否則e必須是可接收該值的類型的指針。如果輸入結束,方法會返回io.EOF并且不修改e(指向的值)。
### func (\*Decoder) [DecodeValue](https://github.com/golang/go/blob/master/src/encoding/gob/decoder.go#L213 "View Source")
```
func (dec *Decoder) DecodeValue(v reflect.Value) error
```
DecodeValue從輸入流讀取下一個值,如果v是reflect.Value類型的零值(v.Kind() == Invalid),方法丟棄該值;否則它會把該值存入v。此時,v必須代表一個非nil的指向實際存在值的指針或者可寫入的reflect.Value(v.CanSet()為真)。如果輸入結束,方法會返回io.EOF并且不修改e(指向的值)。
## type [Encoder](https://github.com/golang/go/blob/master/src/encoding/gob/encoder.go#L16 "View Source")
```
type Encoder struct {
// 內含隱藏或不導出字段
}
```
Encoder管理將數據和類型信息編碼后發送到連接遠端(的操作)。
### func [NewEncoder](https://github.com/golang/go/blob/master/src/encoding/gob/encoder.go#L33 "View Source")
```
func NewEncoder(w io.Writer) *Encoder
```
NewEncoder返回一個將編碼后數據寫入w的\*Encoder。
### func (\*Encoder) [Encode](https://github.com/golang/go/blob/master/src/encoding/gob/encoder.go#L170 "View Source")
```
func (enc *Encoder) Encode(e interface{}) error
```
Encode方法將e編碼后發送,并且會保證所有的類型信息都先發送。
### func (\*Encoder) [EncodeValue](https://github.com/golang/go/blob/master/src/encoding/gob/encoder.go#L214 "View Source")
```
func (enc *Encoder) EncodeValue(value reflect.Value) error
```
EncodeValue方法將value代表的數據編碼后發送,并且會保證所有的類型信息都先發送。
## type [CommonType](https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L225 "View Source")
```
type CommonType struct {
Name string
Id typeId
}
```
CommonType保存所有類型的成員。這是個歷史遺留“問題”,出于保持binary兼容性才保留,只用于類型描述的編碼。該類型應視為不導出類型。
- 庫
- package achive
- package tar
- package zip
- package bufio
- package builtin
- package bytes
- package compress
- package bzip2
- package flate
- package gzip
- package lzw
- package zlib
- package container
- package heap
- package list
- package ring
- package crypto
- package aes
- package cipher
- package des
- package dsa
- package ecdsa
- package elliptic
- package hmac
- package md5
- package rand
- package rc4
- package rsa
- package sha1
- package sha256
- package sha512
- package subtle
- package tls
- package x509
- package pkix
- package database
- package sql
- package driver
- package encoding
- package ascii85
- package asn1
- package base32
- package base64
- package binary
- package csv
- package gob
- package hex
- package json
- package pem
- package xml
- package errors
- package expvar
- package flag
- package fmt
- package go
- package doc
- package format
- package parser
- package printer
- package hash
- package adler32
- package crc32
- package crc64
- package fnv
- package html
- package template
- package image
- package color
- package palette
- package draw
- package gif
- package jpeg
- package png
- package index
- package suffixarray
- package io
- package ioutil
- package log
- package syslog
- package math
- package big
- package cmplx
- package rand
- package mime
- package multipart
- package net
- package http
- package cgi
- package cookiejar
- package fcgi
- package httptest
- package httputil
- package pprof
- package mail
- package rpc
- package jsonrpc
- package smtp
- package textproto
- package url
- package os
- package exec
- package signal
- package user
- package path
- package filepath
- package reflect
- package regexp
- package runtime
- package cgo
- package debug
- package pprof
- package race
- package sort
- package strconv
- package strings
- package sync
- package atomic
- package text
- package scanner
- package tabwriter
- package template
- package time
- package unicode
- package utf16
- package utf8
- package unsafe