gob是Golang包自带的一个数据结构序列化的编码/解码工具。编码使用Encoder,解码使用Decoder。一种典型的应用场景就是RPC(remote procedure calls)。html
gob和json的pack之类的方法同样,由发送端使用Encoder对数据结构进行编码。在接收端收到消息以后,接收端使用Decoder将序列化的数据变化成本地变量。golang
有一点须要注意,json
结构体中缺省的字段将不会被发送。并且在接收方,并不须要全部的字段都要有对应的结构属性对应。godoc中的这个例子很形象:数据结构
当发送方传递的是struct{A, B int}结构的值的时候,接收方能够容许前9种结构,可是后面4种结构确实不容许的。函数
我的以为这种设定是很符合逻辑的:接收端只接受和发送数据“类似”的数据结构。容许模拟类似,可是不容许矛盾。工具
整型:分为sign int和usign int, 其中从上面例子也看到,int和uint是不能互相编解码的。float和int也是不能互相编解码的。ui
Struct,array,slice是能够被编码的。可是function和channel是不能被编码的。this
bool类型是被看成uint来编码的,0是false,1是true。编码
浮点类型的值都是被看成float64类型的值来编码的spa
String和[]byte传递是uint(byte个数) + byte[]的形式编码的
Slice和array是按照uint(array个数) + 每一个array编码 这样的形式进行编码的
Maps是按照 uint(Map个数) + 键值对 这样的形式进行编码的
Struct是按照一对对(属性名 + 属性值)来进行编码的。其中属性值是其本身对应的gob编码。前面说过,若是有一个属性值为0或空,则这个属性直接被忽略。每一个属性的序号是由编码时候顺序决定的,从0开始顺序递增。Struct在序列化前会以-1表明序列化的开始,以0表明序列化结束。即Struct的序列化是按照 “-1 (0 属性1名字 属性1值) (1 属性2名字 属性2值) 0 ”来进行编码的。
很是重要的一点:
这样才能被包外的函数访问!!(谢谢TreapDB提醒)
对于Encoder和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) }
全部Encoder和Decoder的构造函数都有一个io结构,须要制定你将使用哪一个io进行编码解码的传输。
这点在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.
Decode的参数若是不是nil,那就必定是一个指针了。
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) }
这个function也是没有问题的。
这两个方法是当编解码中有一个字段是interface{}的时候须要对interface{}的可能产生的类型进行注册。具体就看一下下面这个例子:
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{})告诉系统:全部的Interface是有可能为Inner结构的。
在这个例子中,若是你注释了gob.Register, 系统会报错。
RegisterName是和Register同样的效果,只是在Register的同时也为这个类型附上一个别名。
这是两个接口,若是你的数据结构实现了这两个接口,当调用encoder.Encode和decoder.Decode的时候就会调用这两个结构的对应函数
看一下下面这个例子:
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) }
这里个人P实现了GobEncoder接口,所以在enc.Encode的时候会调用func (this *P)GobEncode() ([]byte, error)
固然我这个函数直接返回的是空byte,所以在解码的时候会报错:decode error:gob: type mismatch in decoder: want struct type main.Q; got non-struct
这两个接口暴露出来就表明你为本身定义的结构进行编解码规则制定。固然,若是使用本身的编解码规则,在编码和解码的过程就须要是一对的。
gob包是golang提供的“私有”的编解码方式,文档中也说了它的效率会比json,xml等更高(虽然我也没有验证)。所以在两个Go 服务之间的相互通讯建议不要再使用json传递了,彻底能够直接使用gob来进行数据传递。