Golang Gob编码(gob包的使用详解)


Posted in Golang onMay 07, 2021

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
}

Golang Gob编码(gob包的使用详解)

编码的数据中有空接口类型,传递时赋值的空接口为: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
}

Golang Gob编码(gob包的使用详解)

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
}

Golang Gob编码(gob包的使用详解)

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
}

Golang Gob编码(gob包的使用详解)

注:特别注意:以上代码中的结构体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格式进行编译

然后就解决了~

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
golang interface判断为空nil的实现代码
Apr 24 Golang
Go缓冲channel和非缓冲channel的区别说明
Apr 25 Golang
彻底理解golang中什么是nil
Apr 29 Golang
Golang中interface{}转为数组的操作
Apr 30 Golang
golang elasticsearch Client的使用详解
May 05 Golang
使用golang编写一个并发工作队列
May 08 Golang
Golang 实现获取当前函数名称和文件行号等操作
May 08 Golang
victoriaMetrics库布隆过滤器初始化及使用详解
Apr 05 Golang
Go归并排序算法的实现方法
Apr 06 Golang
golang生成并解析JSON
Apr 14 Golang
golang用type-switch判断interface的实际存储类型
Apr 14 Golang
Go 内联优化让程序员爱不释手
Jun 21 Golang
go mod 安装依赖 unkown revision问题的解决方案
解决golang 关于全局变量的坑
May 06 #Golang
Goland使用Go Modules创建/管理项目的操作
解决goland 导入项目后import里的包报红问题
Go 自定义package包设置与导入操作
goland 设置project gopath的操作
解决Goland 同一个package中函数互相调用的问题
You might like
投票管理程序
2006/10/09 PHP
php 求质素(素数) 的实现代码
2011/04/12 PHP
解析php5配置使用pdo
2013/07/03 PHP
PHP+AJAX实现投票功能的方法
2015/09/28 PHP
PHP有序表查找之插值查找算法示例
2018/02/10 PHP
php连接mysql之mysql_connect()与mysqli_connect()的区别
2020/07/19 PHP
制作特殊字的脚本
2006/06/26 Javascript
走出JavaScript初学困境—js初学
2008/12/29 Javascript
Json对象与Json字符串互转(4种转换方式)
2013/03/27 Javascript
jquery实现点击变换导航样式的方法
2015/08/31 Javascript
js实现图片轮播效果
2015/12/19 Javascript
详解javascript实现自定义事件
2016/01/19 Javascript
浅谈js中的变量名和函数名重名
2017/02/13 Javascript
微信小程序的生命周期的详解
2017/10/19 Javascript
详解Vue中localstorage和sessionstorage的使用
2017/12/22 Javascript
微信小程序出现wx.navigateTo页面不跳转问题的解决方法
2017/12/26 Javascript
对vux点击事件的优化详解
2018/08/28 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
2020/03/10 Javascript
解决Antd Table组件表头不对齐的问题
2020/10/27 Javascript
Python中使用PIPE操作Linux管道
2015/02/04 Python
Django视图之ORM数据库查询操作API的实例
2017/10/27 Python
python数据结构之线性表的顺序存储结构
2018/09/28 Python
Python使用mongodb保存爬取豆瓣电影的数据过程解析
2019/08/14 Python
关于Numpy数据类型对象(dtype)使用详解
2019/11/27 Python
三步解决python PermissionError: [WinError 5]拒绝访问的情况
2020/04/22 Python
python 瀑布线指标编写实例
2020/06/03 Python
Keras 在fit_generator训练方式中加入图像random_crop操作
2020/07/03 Python
python爬虫中url管理器去重操作实例
2020/11/30 Python
python asyncio 协程库的使用
2021/01/21 Python
用css3写出气球样式的示例代码
2017/09/11 HTML / CSS
.NET面试10题
2014/02/24 面试题
摄影实习自我鉴定
2013/09/20 职场文书
生物化工工艺专业应届生求职信
2013/10/08 职场文书
物流仓储计划书
2014/01/10 职场文书
幼儿园小班开学寄语(2016秋季)
2015/12/03 职场文书
一文搞懂php的垃圾回收机制
2021/06/18 PHP