Go之gob包的使用
生活随笔
收集整理的這篇文章主要介紹了
Go之gob包的使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
gob包("encoding/gob")管理gob流——在encoder(編碼器,也就是發送器)和decoder(解碼器,也就是接受器)之間交換的字節流數據(gob 就是 go binary的縮寫)。一般用于傳遞遠端程序調用(RPC)的參數和結果。
要使用gob,通過調用NewEncoder()方法先創建一個編碼器,并向其提供一系列數據;然后在接收端,通過調用NewDecoder()方法創建一個解碼器,它從數據流中恢復數據并將它們填寫進本地變量里。下面會通過幾個例子進行說明。
發送端和接收端的值/類型不需要嚴格匹配。對結構體來說,某一字段(通過字段名進行識別)如果發送端有而接收端沒有,會被忽略;接收端有而發送端沒有的字段也會被忽略;發送端和接收端都有的字段其類型必須是可兼容的;發送端和接收端都會在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 } // 無共同字段名
首先來看一個關于encode/decode結構體數據類型的示例。仔細觀察這個例子,有助理解上面所說的發送端和接收端之間字段匹配的問題。
type P struct {
X, Y, Z int
Name string
}
type Q struct {
X, Y *int32
Name string
}
type R struct {
Y, W int
}
// This example shows the basic usage of the package: Create an encoder,
// transmit some values, receive them with a decoder.
func GobBasic() {
// 初始化 encoder 和 decoder
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf) // will write to buf
decoder := gob.NewDecoder(&buf) // will read from buf
// Encode (send) some values
err := encoder.Encode(P{X: 3, Y: 4, Z: 5, Name: "hello"})
if err != nil {
log.Fatal("Encode error:",err)
}
// case 1
// Decode (receive) and print the values
//var q Q
//err = decoder.Decode(&q)
//if err != nil {
// log.Fatal("Decode error:",err)
//}
//
//// 注意,不能寫成 q.X,因為在接收方,定義的是 int型 指針
//// *(q.X) 與 *q.Y 結果相同,但前者語義更加明確
//fmt.Printf("%d %d %s
", *(q.X), *q.Y, q.Name)
//case 2
//var p P
//err = decoder.Decode(&p)
//if err != nil {
// log.Fatal("Decode error:",err)
//}
//// 這里的接收方和傳入方格式完全一致
//fmt.Printf("%d %d %d %s
", p.X, p.Y, p.Z, p.Name)
// case 3
var r R
err = decoder.Decode(&r)
if err != nil {
log.Fatal("Decode error:",err)
}
//fmt.Printf("%d %d %d %s
", r.X, r.Y, r.Z, r.Name)
// 會輸出如下:因為接收端是根據字段名稱進行匹配的
// r.X undefined (type R has no field or method X)
// r.Z undefined (type R has no field or method Z)
// r.Name undefined (type R has no field or method Name)
fmt.Printf("%d
", r.Y) // ok
}
接著我們看一下encode/decode 接口類型的值是如何操作的。與其他常規的類型(比如結構體)最大的不同在于:需要注冊一個明確的實現該接口的類型。
示例如下:
type Point struct {
X, Y int
}
func (p Point) Hypotenuse() float64 {
// Hypot returns Sqrt(p*p + q*q)
return math.Hypot(float64(p.X), float64(p.Y))
}
type Pythagoras interface {
Hypotenuse() float64
}
// 這個例子展示了如何 encode/decode 一個接口類型(interface{})的值
// 與其他常規的類型(比如結構體)最大的不同在于:
// 需要注冊一個明確的實現該接口的類型
func GobInterface() {
// 我們必須要對encoder和decoder注冊具體的類型,
// 因為通常來說,decoder和encoder是在不同的機器上的。
// 經過“注冊”,解析引擎才能知道實現這一接口的具體類型是什么
// (因為同一個接口可以有多種不同的實現)
gob.Register(Point{})
p1 := Point{X: 3, Y: 4}
fmt.Println(p1.Hypotenuse()) // 5
// 編碼,再解碼,觀察解碼后返回的結果是否一致
b, _ := encode(p1)
p2, _ := decode(b)
fmt.Println(p2.Hypotenuse()) // 5
}
// 編碼,把結構體數據編碼成字節流數據
func encode(p Pythagoras) ([]byte, error) {
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf) // 構造編碼器,并把數據寫進buf中
if err := encoder.Encode(&p); err != nil {
log.Printf("encode error: %v
", err)
return nil, err
}
return buf.Bytes(), nil
}
// 解碼,把字節流數據解析成結構體數據
func decode(b []byte) (Pythagoras, error) {
//var buf bytes.Buffer
bufPtr := bytes.NewBuffer(b) // 返回的類型是 *Buffer,而不是 Buffer。注意一下
decoder := gob.NewDecoder(bufPtr) // 從 bufPtr 中獲取數據
var p Pythagoras
if err := decoder.Decode(&p); err != nil { // 將數據寫進變量 p 中
return Point{}, err
}
return p, nil
}
總結
以上是生活随笔為你收集整理的Go之gob包的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由器安全技术-路由器 安全
- 下一篇: ZfNet解卷积:可视化CNN模型( P