Gob 是 Go 自己的以二進(jìn)制形式序列化和反序列化程序數(shù)據(jù)的格式;可以在 encoding 包中找到。這種格式的數(shù)據(jù)簡(jiǎn)稱(chēng)為 Gob (即 Go binary 的縮寫(xiě))。類(lèi)似于 Python 的 "pickle" 和 Java 的 "Serialization"。
Gob 通常用于遠(yuǎn)程方法調(diào)用(RPCs,參見(jiàn) 15.9 的 rpc 包)參數(shù)和結(jié)果的傳輸,以及應(yīng)用程序和機(jī)器之間的數(shù)據(jù)傳輸。 它和 JSON 或 XML 有什么不同呢?Gob 特定地用于純 Go 的環(huán)境中,例如,兩個(gè)用 Go 寫(xiě)的服務(wù)之間的通信。這樣的話(huà)服務(wù)可以被實(shí)現(xiàn)得更加高效和優(yōu)化。 Gob 不是可外部定義,語(yǔ)言無(wú)關(guān)的編碼方式。因此它的首選格式是二進(jìn)制,而不是像 JSON 和 XML 那樣的文本格式。 Gob 并不是一種不同于 Go 的語(yǔ)言,而是在編碼和解碼過(guò)程中用到了 Go 的反射。
Gob 文件或流是完全自描述的:里面包含的所有類(lèi)型都有一個(gè)對(duì)應(yīng)的描述,并且總是可以用 Go 解碼,而不需要了解文件的內(nèi)容。
只有可導(dǎo)出的字段會(huì)被編碼,零值會(huì)被忽略。在解碼結(jié)構(gòu)體的時(shí)候,只有同時(shí)匹配名稱(chēng)和可兼容類(lèi)型的字段才會(huì)被解碼。當(dāng)源數(shù)據(jù)類(lèi)型增加新字段后,Gob 解碼客戶(hù)端仍然可以以這種方式正常工作:解碼客戶(hù)端會(huì)繼續(xù)識(shí)別以前存在的字段。并且還提供了很大的靈活性,比如在發(fā)送者看來(lái),整數(shù)被編碼成沒(méi)有固定長(zhǎng)度的可變長(zhǎng)度,而忽略具體的 Go 類(lèi)型。
假如在發(fā)送者這邊有一個(gè)有結(jié)構(gòu) T:
type T struct { X, Y, Z int }
var t = T{X: 7, Y: 0, Z: 8}
而在接收者這邊可以用一個(gè)結(jié)構(gòu)體 U 類(lèi)型的變量 u 來(lái)接收這個(gè)值:
type U struct { X, Y *int8 }
var u U
在接收者中,X 的值是7,Y 的值是0(Y的值并沒(méi)有從 t 中傳遞過(guò)來(lái),因?yàn)樗橇阒担?/p>
和 JSON 的使用方式一樣,Gob 使用通用的 io.Writer 接口,通過(guò) NewEncoder() 函數(shù)創(chuàng)建 Encoder 對(duì)象并調(diào)用 Encode();相反的過(guò)程使用通用的 io.Reader 接口,通過(guò) NewDecoder() 函數(shù)創(chuàng)建 Decoder 對(duì)象并調(diào)用 Decode。
我們把示例 12.12 的信息寫(xiě)進(jìn)名為 vcard.gob 的文件作為例子。這會(huì)產(chǎn)生一個(gè)文本可讀數(shù)據(jù)和二進(jìn)制數(shù)據(jù)的混合,當(dāng)你試著在文本編輯中打開(kāi)的時(shí)候會(huì)看到。
在示例 12.18 中你會(huì)看到一個(gè)編解碼,并且以字節(jié)緩沖模擬網(wǎng)絡(luò)傳輸?shù)暮?jiǎn)單例子:
示例 12.18 gob1.go:
// gob1.go
package main
import (
"bytes"
"fmt"
"encoding/gob"
"log"
)
type P struct {
X, Y, Z int
Name string
}
type Q struct {
X, Y *int32
Name string
}
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) 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.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
// Output: "Pythagoras": {3,4}
示例 12.19 gob2.go 編碼到文件:
// gob2.go
package main
import (
"encoding/gob"
"log"
"os"
)
type Address struct {
Type string
City string
Country string
}
type VCard struct {
FirstName string
LastName string
Addresses []*Address
Remark string
}
var content string
func main() {
pa := &Address{"private", "Aartselaar","Belgium"}
wa := &Address{"work", "Boom", "Belgium"}
vc := VCard{"Jan", "Kersschot", []*Address{pa,wa}, "none"}
// fmt.Printf("%v: \n", vc) // {Jan Kersschot [0x126d2b80 0x126d2be0] none}:
// using an encoder:
file, _ := os.OpenFile("vcard.gob", os.O_CREATE|os.O_WRONLY, 0666)
defer file.Close()
enc := gob.NewEncoder(file)
err := enc.Encode(vc)
if err != nil {
log.Println("Error in encoding gob")
}
}
練習(xí) 12.8:degob.go:
寫(xiě)一個(gè)程序讀取 vcard.gob 文件,解碼并打印它的內(nèi)容。