Golang Gob编码(gob包的使用详解)
作者:cqu_jiangzhou 时间:2024-02-22 02:16:46
gob是Golang包自带的一个数据结构序列化的编码/解码工具。编码使用Encoder,解码使用Decoder。一种典型的应用场景就是RPC(remote procedure calls)。
gob和json的pack之类的方法一样,由发送端使用Encoder对数据结构进行编码。在接收端收到消息之后,接收端使用Decoder将序列化的数据变化成本地变量。
基本使用
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
}
var network bytes.Buffer //网络传递的数据载体
func main() {
err := senMsg()
if err!=nil {
fmt.Println("编码错误")
return
}
err = revMsg()
if err!=nil {
fmt.Println("解码错误")
return
}
}
func senMsg()error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network)
sendMsg:=MsgData{3, 4, 5, "jiangzhou"}
fmt.Println("原始数据:",sendMsg)
err := enc.Encode(&sendMsg)
fmt.Println("传递的编码数据为:",network)
return err
}
func revMsg()error {
var revData MsgData
dec:=gob.NewDecoder(&network)
err:= dec.Decode(&revData) //传递参数必须为 地址
fmt.Println("解码之后的数据为:",revData)
return err
}
Register和RegisterName
1、编码的数据中有空接口类型,传递时赋值的空接口为:基本类型(int、float、string)、切片时,可以不进行注册。
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
Msg interface{}
}
var network bytes.Buffer //网络传递的数据载体
func main() {
err := senMsg()
if err!=nil {
fmt.Println("编码错误")
return
}
err = revMsg()
if err!=nil {
fmt.Println("解码错误")
return
}
}
func senMsg()error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network)
s:=make([]string,0)
s=append(s, "hello")
//sendMsg:=MsgData{3, 4, 5, "jiangzhou",Msg{10001,"hello"}}
//sendMsg:=MsgData{3, 4, 5, "jiangzhou",66.66}
sendMsg:=MsgData{3, 4, 5, "jiangzhou",s}
fmt.Println("原始数据:",sendMsg)
err := enc.Encode(&sendMsg)
fmt.Println("传递的编码数据为:",network)
return err
}
func revMsg()error {
var revData MsgData
dec:=gob.NewDecoder(&network)
err:= dec.Decode(&revData) //传递参数必须为 地址
fmt.Println("解码之后的数据为:",revData)
return err
}
编码的数据中有空接口类型,传递时赋值的空接口为:map、struct时,必须进行注册。
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
Msg interface{}
}
var network bytes.Buffer //网络传递的数据载体
func main() {
err := senMsg()
if err!=nil {
fmt.Println("编码错误")
return
}
err = revMsg()
if err!=nil {
fmt.Println("解码错误")
return
}
}
func senMsg()error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network)
m:=make(map[int]string)
m[10001]="hello"
m[10002]="jiangzhou"
sendMsg:=MsgData{3, 4, 5, "jiangzhou",m}
fmt.Println("原始数据:",sendMsg)
err := enc.Encode(&sendMsg)
fmt.Println("传递的编码数据为:",network)
return err
}
func revMsg()error {
var revData MsgData
dec:=gob.NewDecoder(&network)
err:= dec.Decode(&revData) //传递参数必须为 地址
fmt.Println("解码之后的数据为:",revData)
return err
}
Register和RegisterName解决的主要问题是:当编解码中有一个字段是interface{}(interface{}的赋值为map、结构体时)的时候需要对interface{}的可能产生的类型进行注册。
正确代码为:
interface{}的赋值为map时:
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
Msg interface{}
}
var network bytes.Buffer //网络传递的数据载体
func main() {
err := senMsg()
if err!=nil {
fmt.Println("编码错误")
return
}
err = revMsg()
if err!=nil {
fmt.Println("解码错误")
return
}
}
func senMsg()error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network)
m:=make(map[int]string)
m[10001]="hello"
m[10002]="jiangzhou"
gob.Register(map[int]string{}) //TODO:进行了注册
sendMsg:=MsgData{3, 4, 5, "jiangzhou",m}
fmt.Println("原始数据:",sendMsg)
err := enc.Encode(&sendMsg)
fmt.Println("传递的编码数据为:",network)
return err
}
func revMsg()error {
var revData MsgData
dec:=gob.NewDecoder(&network)
err:= dec.Decode(&revData) //传递参数必须为 地址
fmt.Println("解码之后的数据为:",revData)
return err
}
interface{}的赋值为结构体时:
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
Msg interface{}
}
var network bytes.Buffer //网络传递的数据载体
func main() {
err := senMsg()
if err != nil {
fmt.Println("编码错误",err)
return
}
err = revMsg()
if err != nil {
fmt.Println("解码错误")
return
}
}
type Msg struct {
Id int
Detail string
}
func senMsg() error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network)
gob.Register(Msg{}) //TODO:进行了注册
s:=Msg{10001,"hello jiangzhou"}
sendMsg := MsgData{3, 4, 5, "jiangzhou", s}
fmt.Println("原始数据:", sendMsg)
err := enc.Encode(&sendMsg)
fmt.Println("传递的编码数据为:", network)
return err
}
func revMsg() error {
var revData MsgData
dec := gob.NewDecoder(&network)
err := dec.Decode(&revData) //传递参数必须为 地址
fmt.Println("解码之后的数据为:", revData)
return err
}
注:特别注意:以上代码中的结构体Msg对应的成员变量名称首字母一定要大写,不然会出现:编码错误编码错误 gob: type main.Msg has no exported fields
这里使用了
gob.Register(Msg{})
告诉系统:所有的Interface是有可能为Msg结构的。
在这个例子中,如果你注释了gob.Register, 系统会报错。
RegisterName是和Register一样的效果,只是在Register的同时也为这个类型附上一个别名。
补充:GO语音gob包的系列化和反序列化使用和遇到的错误
encoding/gob包实现了高效的序列化,特别是数据结构较复杂的,结构体、数组和切片都被支持。
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
//定义一个结构体
type Person struct {
Age int
Name string
}
func main() {
p1:=Person{
Age: 18,
Name: "贪吃的猪",
}
//序列化
//这里是储存的buffer
var bufferr bytes.Buffer
PerEncod:=gob.NewEncoder(&bufferr) //1.创建一个编码器
err:=PerEncod.Encode(&p1) //编码
if err != nil {
fmt.Println("编码器 解码错误",err)
return
}
//现在buffer就是完成储存序列化的
fmt.Printf("序列化:buf%x\n",bufferr)
//创建一个空的结构体来接受
p2 :=Person{}
//反序列化
PerDecod:=gob.NewDecoder(bytes.NewReader(bufferr.Bytes()))//创建一个反编码器
err=PerDecod.Decode(&p2)
if err != nil {
fmt.Println("PerDecod.Decode err:",err)
return
}
fmt.Println("反序列化:",p2)
//fmt.Printf("反序列化数据:string",p2)
}
系列化和反系列化的常见的错误
如果是你的结构体的字段是小写开头 gob序列化你的结构体的时候会找不到字段
如果我把
type Person struct {
Age int
Name string
}
改成
type Person struct {
age int
name string
}
编码器 解码错误 gob: type main.Person has no exported fields
解决方法就是把字段开头变成大写
这个错误还有一种可能造成的 你定义的结构里面还有一个结构 2
这个结构2的字段全部都是小写开头
解决方法就是把字段开头变成大写
今天是2019年11月2日 11:32 我的一个改了半天的bug 终于解决
gob在编译的时候 如果你的这个结构体里面包含另一个结构体
但是另一个结构体的字段开头没有大写
gob编译的时候是不会报错,他会不要没有大写的字段,
你反序列化的时候会发现这个字段是nil 空值
我去你码的
今天是2019年11月4日,今天新的序列化bug出現了
我生成秘钥对然后对密钥对进行数据序列化然后储存在文件里面
然后错误提示,在, gob: type not registered for interface: elliptic.p256Curve
其实gob是可以序列化全部结构,但是它不能序列化interface接口
因为接口的大小是无法定义的
密钥对的中的公钥结构体里面一个字段elliptic.Curve 他是接口
我们把这个接口进行注册就行了
gob提供了一个函数可以进行注册
gob.Register(elliptic.P256())
要gob遇到这个接口的时候按照elliptic.P256格式进行编译
然后就解决了~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://blog.csdn.net/weixin_42117918/article/details/105864520


猜你喜欢
Python中内建模块collections如何使用
Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例

Python实现扫码工具的示例代码
Python反射的用法实例分析
Python中shutil模块的学习笔记教程
Python数据处理的三个实用技巧分享

实例介绍Python中整型
asp fckeditor自定义上传文件的文件名
Javascript removeChild()删除节点及删除子节点的方法

vue打包之后生成一个配置文件修改接口的方法

PHP设计模式之模板方法模式Template Method Pattern详解
理解Python垃圾回收机制
SQL Server 2005 五个动态管理对象
Python结合ImageMagick实现多张图片合并为一个pdf文件的方法

python 中的9个实用技巧,助你提高开发效率
电子商务网站评论设计探讨

浅谈django2.0 ForeignKey参数的变化
vuex 多模块时 模块内部的mutation和action的调用方式

PHP函数之error_reporting(E_ALL ^ E_NOTICE)详细说明
SQL优化老出错,那是你没弄明白MySQL解释计划用法
