注意到 encoding/gob
包是因为看到 net/rpc
包使用它编解码。
二者都是标准库下的包。
一、示例代码和执行结果
// hello.go
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type Request struct {
ServiceMethod string // format: "Service.Method"
Seq uint64 // sequence number chosen by client
next *Request // for free list in Server
}
type Request3 struct {
ServiceMethod string
}
type Request4 struct {
Other int64
}
func main() {
var err error
a := &bytes.Buffer{}
encoder := gob.NewEncoder(a)
_ = encoder.Encode(&Request{
Seq: 23,
ServiceMethod: "firstMethod",
})
_ = encoder.Encode(&Request{
Seq: 9,
ServiceMethod: "secondMethod",
})
_ = encoder.Encode(&Request{
Seq: 16,
ServiceMethod: "thirdMethod",
})
_ = encoder.Encode(&Request{
Seq: 77,
ServiceMethod: "fourthMethod",
})
fmt.Printf("buf: %#v\n\n", a)
b := bytes.NewBufferString(a.String())
decoder := gob.NewDecoder(b)
ans1 := &Request{}
_ = decoder.Decode(ans1)
fmt.Println("ans1 err: ", err)
fmt.Printf("ans1: %#v\n\n", ans1)
ans2 := &Request{}
err = decoder.Decode(ans2)
fmt.Println("ans2 err: ", err)
fmt.Printf("ans2: %#v\n\n", ans2)
ans3 := &Request3{}
err = decoder.Decode(ans3)
fmt.Println("ans3 err: ", err)
fmt.Printf("ans3: %#v\n\n", ans3)
ans4 := &Request4{}
err = decoder.Decode(ans4)
fmt.Println("ans4 err: ", err)
fmt.Printf("ans4: %#v\n\n", ans4)
ans5 := &Request{}
err = decoder.Decode(ans5)
fmt.Println("ans5 err: ", err)
fmt.Printf("ans5: %#v\n\n", ans5)
}
$ go run ./hello.go
buf: &bytes.Buffer{buf:[]uint8{0x2f, 0xff, 0x81, 0x3, 0x1, 0x1, 0x7, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1, 0xff, 0x82, 0x0, 0x1, 0x2, 0x1, 0xd, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0xc, 0x0, 0x1, 0x3, 0x53, 0x65, 0x71, 0x1, 0x6, 0x0, 0x0, 0x0, 0x12, 0xff, 0x82, 0x1, 0xb, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x17, 0x0, 0x13, 0xff, 0x82, 0x1, 0xc, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x9, 0x0, 0x12, 0xff, 0x82, 0x1, 0xb, 0x74, 0x68, 0x69, 0x72, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x10, 0x0, 0x13, 0xff, 0x82, 0x1, 0xc, 0x66, 0x6f, 0x75, 0x72, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x4d, 0x0}, off:0, lastRead:0}
ans1 err:
ans1: &main.Request{ServiceMethod:"firstMethod", Seq:0x17, next:(*main.Request)(nil)}
ans2 err:
ans2: &main.Request{ServiceMethod:"secondMethod", Seq:0x9, next:(*main.Request)(nil)}
ans3 err:
ans3: &main.Request3{ServiceMethod:"thirdMethod"}
ans4 err: gob: type mismatch: no fields matched compiling decoder for Request4
ans4: &main.Request4{Other:0}
ans5 err: EOF
ans5: &main.Request{ServiceMethod:"", Seq:0x0, next:(*main.Request)(nil)}
二、解读
以上代码一次性编码写入 4 条数据,分 5 次读取、解码。
- ans1、ans2 能正确解读,说明
gob
能准确识别边界; - ans3 能正确解读,
gob
解码的时候不在乎结构具体叫什么,但在乎其中的具体字段; - ans4 解读提示
type mismatch
,说明想要准确解读需要数据写入方、读取方彼此协调好,使用相同的数据结构; - ans5 传入的数据结构能对应上第 4 条输入,但没能解读到数据,提示
EOF
,说明 ans4 虽然没能准确解读,但使用了gob
解码需要的信息。
综合以上,可以归纳 gob
使用的特点
1、可先不读取解码,一次性多条编码写入;
2、读取解码时,可自动识别每一条信息的边界;
3、每次读取解码时,先取出一条编码信息,再同传入的指定结构匹配并填充,失败时数据不会放回;
4、解码时发现没有数据,报错 EOF
。
另:编、解码传入的指定结构都需要是指针类型。