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來進行數據傳遞。