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 实现菜单树的生成方式
Apr 28 Golang
完美解决golang go get私有仓库的问题
May 05 Golang
Golang二维数组的使用方式
May 28 Golang
Go语言应该什么情况使用指针
Jul 25 Golang
Golang并发操作中常见的读写锁详析
Aug 30 Golang
Golang表示枚举类型的详细讲解
Sep 04 Golang
Go语言实现一个简单的并发聊天室的项目实战
Mar 18 Golang
Go语言 详解net的tcp服务
Apr 14 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
Golang MatrixOne使用介绍和汇编语法
Apr 19 Golang
Golang map映射的用法
Apr 22 Golang
Golang 实现 WebSockets 之创建 WebSockets
Apr 24 Golang
go mod 安装依赖 unkown revision问题的解决方案
解决golang 关于全局变量的坑
May 06 #Golang
Goland使用Go Modules创建/管理项目的操作
解决goland 导入项目后import里的包报红问题
Go 自定义package包设置与导入操作
goland 设置project gopath的操作
解决Goland 同一个package中函数互相调用的问题
You might like
PHP脚本的10个技巧(8)
2006/10/09 PHP
发布一个用PHP fsockopen写的HTTP下载的类
2007/02/22 PHP
PHP教程 基本语法
2009/10/23 PHP
php empty函数判断mysql表单是否为空
2010/04/12 PHP
php设计模式 Facade(外观模式)
2011/06/26 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
js一组验证函数
2008/12/20 Javascript
JavaScript入门之事件、cookie、定时等
2011/10/21 Javascript
js关闭浏览器窗口及检查浏览器关闭事件
2013/09/03 Javascript
js实现二代身份证号码验证详解
2014/11/20 Javascript
jQuery Validate验证框架经典大全
2015/09/23 Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【一】
2016/05/10 Javascript
使用jQuery判断浏览器滚动条位置的方法
2016/05/30 Javascript
JavaScript中捕获/阻止捕获、冒泡/阻止冒泡方法
2016/12/07 Javascript
JavaScript实现简单生成随机颜色的方法
2017/09/21 Javascript
js+css实现红包雨效果
2018/07/12 Javascript
vue组件从开发到发布的实现步骤
2018/11/11 Javascript
Vue基础学习之项目整合及优化
2019/06/02 Javascript
node爬取新型冠状病毒的疫情实时动态
2020/02/06 Javascript
[03:04]2018年国际邀请赛典藏宝瓶&莱恩声望物品展示 片尾有彩蛋
2018/06/04 DOTA
python邮件发送smtplib使用详解
2020/06/16 Python
从django的中间件直接返回请求的方法
2018/05/30 Python
python利用selenium进行浏览器爬虫
2019/04/25 Python
python plotly绘制直方图实例详解
2019/07/22 Python
Python3的unicode编码转换成中文的问题及解决方案
2019/12/10 Python
python字符串判断密码强弱
2020/03/18 Python
python能自学吗
2020/06/18 Python
使用html5制作loading图的示例
2014/04/14 HTML / CSS
联想中国官方商城:Lenovo China
2017/10/18 全球购物
英国户外装备和冒险服装零售商:alloutdoor
2018/01/30 全球购物
澳大利亚网上玩具商店:Mr Toys Toyworld
2018/03/25 全球购物
俄罗斯购买剧院和演唱会门票网站:Parter.ru
2019/11/09 全球购物
Expedia瑞典官网:预订度假屋、酒店、汽车租赁、机票等
2021/01/23 全球购物
中学生运动会新闻稿
2014/09/24 职场文书
2019让人心动的商业计划书
2019/06/27 职场文书
win10电脑双屏显示一个黑屏怎么办?win10电脑双屏显示一个黑屏解决方法
2022/07/15 数码科技