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判断key是否在map中的代码
Apr 24 Golang
win10下go mod配置方式
Apr 25 Golang
go语言中切片与内存复制 memcpy 的实现操作
Apr 27 Golang
浅谈golang 中time.After释放的问题
May 05 Golang
golang switch语句的灵活写法介绍
May 06 Golang
Go 自定义package包设置与导入操作
May 06 Golang
基于Golang 高并发问题的解决方案
May 08 Golang
Golang流模式之grpc的四种数据流
Apr 13 Golang
Golang Elasticsearches 批量修改查询及发送MQ
Apr 19 Golang
Golang 结构体数据集合
Apr 22 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 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
取得单条网站评论以数组形式进行输出
2014/07/28 PHP
php类的扩展和继承用法实例
2015/06/20 PHP
基于PHP的加载类操作以及其他两种魔术方法的应用实例
2017/08/28 PHP
SWFObject Flash js调用类
2008/07/08 Javascript
js获取指定日期前后的日期代码
2013/08/20 Javascript
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
js的各种排序算法实现(总结)
2016/07/23 Javascript
js 提交form表单和设置form表单请求路径的实现方法
2016/10/25 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
详解javascript表单的Ajax提交插件的使用
2016/12/29 Javascript
简单实现jQuery多选框功能
2017/01/09 Javascript
JS实现旋转木马式图片轮播效果
2017/01/18 Javascript
JS中cookie的使用及缺点讲解
2017/05/13 Javascript
JavaScript制作简单的框选图表
2017/05/15 Javascript
AngularJS实现页面跳转后自动弹出对话框实例代码
2017/08/02 Javascript
基于js中的存储键值对以及注意事项介绍
2018/03/30 Javascript
vue实现动态添加数据滚动条自动滚动到底部的示例代码
2018/07/06 Javascript
[02:08]2018年度CS GO枪械皮肤设计大赛优秀作者-完美盛典
2018/12/16 DOTA
Python入门及进阶笔记 Python 内置函数小结
2014/08/09 Python
用Python编写简单的微博爬虫
2016/03/04 Python
Python切换pip安装源的方法详解
2016/11/18 Python
python实现逻辑回归的方法示例
2017/05/02 Python
使用CodeMirror实现Python3在线编辑器的示例代码
2019/01/14 Python
python3 深浅copy对比详解
2019/08/12 Python
Python中关于浮点数的冷知识
2019/09/22 Python
python Pillow图像处理方法汇总
2019/10/16 Python
pytorch 实现在预训练模型的 input上增减通道
2020/01/06 Python
pymysql之cur.fetchall() 和cur.fetchone()用法详解
2020/05/15 Python
CSS3中使用RGBa来调节透明度的教程
2016/05/09 HTML / CSS
英国男士时尚网站:Dandy Fellow
2018/02/09 全球购物
秋收起义观后感
2015/06/11 职场文书
植树节新闻稿
2015/07/17 职场文书
军事理论课感想
2015/08/11 职场文书
Python利器openpyxl之操作excel表格
2021/04/17 Python
JavaScript利用html5新方法操作元素类名详解
2021/11/27 Javascript