Go语言 encoding/gob包
数据 在 网络传输 保存至文件 需要用到 编码 解码
编码方式 JSON / XML / Google 的 protocol buffers / Go 的 gob 包 等

1 golang中的gob包是什么
2 go标准库中 gob编码规则
3 gob包 给开发者提供了什么内容 怎么使用
4 gob 目的是什么 及应用场景有哪些

一 golang中的gob包
gob是golang包 带 数据结构 序列化的 编码/解码工具

二 go标准库中的gob编码规则
当发生方传递的是struct{A,B int}结构的值 接收方可以允许前9种结构 但是后4四种结构却是不允许的

允许模拟相似 但是不允许矛盾
各个类型的编码规则
1 结构体内 只有 导出字段 且 导出字段 才能被编码和解码
2 编码至少存在一个可编码字段 解码 也至少需要一个能被解码字段 不然会报错
3 解码方的导出字段必须存在与编码后的同名字段 类型一致 或 接收方为同类型指针 或为指向指针的指针类型 (比如 编码 A int 则解码可以为A int A *int A **int 这三种的一种 虽然A ***int不会报错 但是接收不到值) 如果导出字段名称一样 但是类型不一样(排除前面的那些情况)的话 就会报错

三 gob包给开发者提供了什么内容 怎么使用
结构体
type GobDecoder interface
type GobEncoder interface
type Decoder struct
type Encoder struct

函数列表
func Register(value interface{})
func RegisterName(name string, value interface{})
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(e interface{}) error
func (dec *Decoder) DecoderValue(v reflect.Value) error
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(e interface{}) error
func (enc *Encoder) EncodeValue(value reflect.Value) error

详解
type GobDecoder interface {
        GobEecode([]byte) error
}
GobDecoder是一个描述数据的接口 提供自己的方案来解码 GobEncoder 发送的数据

type GobEncoder interface {
        GobEncode() ([]byte, error)
}
GobEncoder 是 描述数据的接口 提供自己的方案来将数据编码提供GobDecoder接收并解码 一个实现了GobEncoder接口和GobDecoder接口的类型可以完全控制自身数据的表示 因此可以包含非导出字段 通道 函数等数据 这些数据gob流正常是不能传输的
// A Decoder manages the receipt of type and data information read from the remote side of a connection.
type Decoder struct {
  mutex        sync.Mutex                              // each item must be received atomically
  r            io.Reader                               // source of the data
  buf          bytes.Buffer                            // buffer for more efficient i/o from r
  wireType     map[typeId]*wireType                    // map from remote ID to local description
  decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
  ignorerCache map[typeId]**decEngine                  // ditto for ignored objects
  freeList     *decoderState                           // list of free decoderStates; avoids reallocation
  countBuf     []byte                                  // used for decoding integers while parsing messages
  tmp          []byte                                  // temporary storage for i/o; saves reallocating
  err          error
}
// An Encoder manages the transmission of type and data information to the other side of a connection.
type Encoder struct {
    mutex      sync.Mutex              // each item must be sent atomically
    w          []io.Writer             // where to send the data
    sent       map[reflect.Type]typeId // which types we've already sent
    countState *encoderState           // stage for writing counts
    freeList   *encoderState           // list of free encoderStates; avoids reallocation
    byteBuf    bytes.Buffer            // buffer for top-level encoderState
    err        error
}
1 func Register(value interface{})
Register记录value下层具体值得类型和其名称 该名称将用来识别发送或接收接口类型值下层的具体类型 本函数只应在初始化调用 如果类型和名字的映射不是一一对应的 会panic

2 func RegisterName(name string, value interface{})
RegisterName 使用自定义的名称替代类型的默认名称

3 func NewDecoder(r io.Reader) *Decoder

参数列表 r  Reader对象
返回值   *Decoder  指向Decoder的指针
功能说明  主要是给r创建一个decoder实例

4 func (des *Decoder) Decode(e interface{}) error
参数列表 e  空接口类型 可以处理任何类型的数据
返回值 error
功能说明 是Decoder的方法即(method) 需要使用NewDcoder()创建*Decoder对象后 才可以使用

5 func (dec *Decoder) DecodeValue(v refletc.Value) error

6 func NewEncoder(w io.Writer) *Encoder

7 func (enc *Encoder) Encode(e interface{}) error

参数列表 v  序列化gob对象
返回值 error错误
功能说明 这个函数主要是讲encode编码的gob数据写入到相关联的对象

8 func (enc *Encoder) EncodeValue(value reflect.Value) error
gob自定义内容
gob的包主要分两块内容 一是自定义gob规则 二是基于go标准库中已实现的gob进行编解码操作

demo1 自定义gob规则
1 实现GobDecoder GobEncoder这两个接口
2 编写代码

package main
import (
    "encoding/gob"
    "os"
    "fmt"
)

type gobSend struct {
    A int
    B float64
}

type gobGet struct {
    A int
    D float64
}

func init() {
    gob.Register(&gobSend{})
    gob.Register(&gobGet{})
}

func main() {
    fmt.Println(gobEncode("1.gob"))
    fmt.Println(gobDecode("1.gob"))
}

func gobEncode(fileName string) error {
    fi, err := os.Create(fileName)
    if err != nil {
        return err
    }
    defer fi.Close()

    encoder := gob.NewEncoder(fi)
    return encoder.Encode(gobSend{1,12})
}

func gobDecode(fileName string) (error) {
    fi, err := os.Open(fileName)
    if err != nil {
        return err
    }
    defer fi.Close()

    decoder := gob.NewDecoder(fi)
    g := gobGet{}
    err = decoder.Decode(&g)
    fmt.Println(g)
    return err
}

四 gob 目的是什么 应用场景
数据结构能够在网络上传输或能够保存到文件中 gob可以通过json或gob来序列化struct对象
gob编码可以实现json所不能支持的struct方法序列化
但是gob是golang提供的“私有”的编码方式 go服务之间通信可以使用gob传输
 
编码 Encoder 解码 Decoder 典型 应用场景 RPC(remote procedure calls)

gob 由发送端 Encoder 对数据结构 编码 在 接收端 Decoder 数据 化成 本地变量
gob 编码可 实现 json 所不能支持的 struct 方法序列化 利用gob包序列化 struct 保存到本地 十分简单

Package gob manages streams of gobs
binary values exchanged between an Encoder (transmitter) and a Decoder (receiver).
A typical use is transporting arguments and results of remote procedure calls (RPCs) such as those provided by package "net/rpc"

注册方法
func Register(value interface{})
Register records a type, identified by a value for that type, under its internal type name.

func NewDecoder(r io.Reader) *Decoder
NewDecoder returns a new decoder that reads from the io.Reader

func (dec *Decoder) Decode(e interface{}) error
Decode reads the next value from the input stream and stores it in the data represented by the empty interface value.

func NewEncoder(w io.Writer) *Encoder
NewEncoder returns a new encoder that will transmit on the io.Writer

func (enc *Encoder) Encode(e interface{}) error
Encode transmits the data item represented by the empty interface value, guaranteeing that all necessary type information has been transmitted first.

gob只能用在golang中 所以在实际工程开发过程中 如果与其他端 或 其他语言打交道 那么gob是不可以的  就要 用json了
Gob is much more preferred when communicating between Go programs. However, gob is currently supported only in Go and, well, C, so only ever use that when you’re sure no program written in any other programming language will try to decode the values.

gob的优势
发送方的结构和接受方的结构并不需要完全一致 例如定义一个结构体
struct { A, B int }
下面的类型都是可以发送 接收的
struct { A, B int } // the same
*struct { A, B int }    // extra indirection of the struct
struct { *A, **B int }  // extra indirection of the fields
struct { A, B int64 }   // different concrete value type; see below

以下可以接收
struct { A, B int } // the same
struct { B, A int } // ordering doesn't matter; matching is by name
struct { A, B, C int }  // extra field (C) ignored
struct { B int }    // missing field (A) ignored; data will be dropped
struct { B, C int } // missing field (A) ignored; extra field (C) ignored.


下面的格式是有问题
struct { A int; B uint }    // change of signedness for B
struct { A int; B float }   // change of type for B
struct { }          // no field names in common
struct { C, D int }     // no field names in common

应用 官方的文档和例子 //golang.org/pkg/encoding/gob/

package main
import (
    "bytes"
    "encoding/gob"
    "fmt"
)
type MyFace interface {
    A()
}
type Cat struct{}
type Dog struct{}

func (c *Cat) A() {
    fmt.Println("Meow")
}
func (d *Dog) A() {
    fmt.Println("Woof")
}
func init() {
    // This type must match exactly what your going to be using,down to whether or not its a pointer
    gob.Register(&Cat{})
    gob.Register(&Dog{})
}

func main() {
    network := new(bytes.Buffer)
    enc := gob.NewEncoder(network)

    var inter MyFace
    inter = new(Cat)

    // Note: pointer to the interface
    err := enc.Encode(&inter)
    if err != nil {
        panic(err)
    }

    inter = new(Dog)
    err = enc.Encode(&inter)
    if err != nil {
        panic(err)
    }

    // Now lets get them back out
    dec := gob.NewDecoder(network)

    var get MyFace
    err = dec.Decode(&get)
    if err != nil {
        panic(err)
    }

    // Should meow
    get.A()

    err = dec.Decode(&get)
    if err != nil {
        panic(err)
    }

    // Should woof
    get.A()

}
gob包 实现的序列化 struct 对象保存到本地 利用gob 反序列化本地的struct对象
package main
import (
    "encoding/gob"
    "fmt"
    "os"
    "runtime"
)
const file = "./test.gob"
type User struct {
    Name, Pass string
}
func main() {
    var datato = &User{"Donald", "DuckPass"}
    var datafrom = new(User)
    err := Save(file, datato)
    Check(err)
    err = Load(file, datafrom)
    Check(err)
    fmt.Println(datafrom)
}

// Encode via Gob to file
func Save(path string, object interface{}) error {
    file, err := os.Create(path)
    if err == nil {
        encoder := gob.NewEncoder(file)
        encoder.Encode(object)
    }
    file.Close()
    return err
}

// Decode Gob file
func Load(path string, object interface{}) error {
    file, err := os.Open(path)
    if err == nil {
        decoder := gob.NewDecoder(file)
        err = decoder.Decode(object)
    }
    file.Close()
    return err
}

func Check(e error) {
    if e != nil {
        _, file, line, _ := runtime.Caller(1)
        fmt.Println(line, "\t", file, "\n", e)
        os.Exit(1)
    }
}
输出 &{Donald DuckPass}