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
golang如何去除多余空白字符(含制表符)
Apr 25 Golang
Go timer如何调度
Jun 09 Golang
Go遍历struct,map,slice的实现
Jun 13 Golang
go goroutine 怎样进行错误处理
Jul 16 Golang
Golang 并发下的问题定位及解决方案
Mar 16 Golang
Golang原生rpc(rpc服务端源码解读)
Apr 07 Golang
Golang流模式之grpc的四种数据流
Apr 13 Golang
golang生成并解析JSON
Apr 14 Golang
golang使用map实现去除重复数组
Apr 14 Golang
Golang map映射的用法
Apr 22 Golang
Golang ort 中的sortInts 方法
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模糊查询的实现方法(推荐)
2016/09/06 PHP
php实现微信支付之现金红包
2018/05/30 PHP
对laravel in 查询的使用方法详解
2019/10/09 PHP
jquery $.ajax()取xml数据的小问题解决方法
2010/11/20 Javascript
jquery $.getJSON()跨域请求
2011/12/21 Javascript
只需20行代码就可以写出CSS覆盖率测试脚本
2013/04/24 Javascript
JS删除字符串中重复字符方法
2014/03/09 Javascript
javascript 原型链维护和继承详解
2014/11/26 Javascript
基于canvas实现的绚丽圆圈效果完整实例
2016/01/26 Javascript
js生成随机数(指定范围)的实例代码
2016/07/10 Javascript
jQuery为动态生成的select元素添加事件的方法
2016/08/29 Javascript
vue-router 中router-view不能渲染的解决方法
2017/05/23 Javascript
angularJs利用$scope处理升降序的方法
2018/10/08 Javascript
layui操作列按钮个数和文字颜色的判断实例
2019/09/11 Javascript
[00:32]2018DOTA2亚洲邀请赛Newbee出场
2018/04/03 DOTA
[01:01:13]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第三场
2018/04/06 DOTA
python实现文本去重且不打乱原本顺序
2016/01/26 Python
python制作企业邮箱的爆破脚本
2016/10/05 Python
启动Atom并运行python文件的步骤
2018/11/09 Python
浅谈python的输入输出,注释,基本数据类型
2019/04/02 Python
Python3实现计算两个数组的交集算法示例
2019/04/03 Python
Python3.5运算符操作实例详解
2019/04/25 Python
django数据关系一对多、多对多模型、自关联的建立
2019/07/24 Python
Python pandas用法最全整理
2019/08/04 Python
详解查看Python解释器路径的两种方式
2020/10/15 Python
详解CSS3选择器的使用方法汇总
2015/11/24 HTML / CSS
详解CSS3的box-shadow属性制作边框阴影效果的方法
2016/05/10 HTML / CSS
HTML5 Canvas像素处理使用接口介绍
2012/12/02 HTML / CSS
实习自我鉴定模板
2013/09/28 职场文书
审核会计岗位职责
2013/11/08 职场文书
美术教学感言
2014/02/22 职场文书
优秀大学生求职自荐信范文
2014/04/19 职场文书
环保建议书300字
2014/05/14 职场文书
危货运输企业安全生产责任书
2014/07/28 职场文书
《落花生》教学反思
2016/02/16 职场文书
解决redis sentinel 频繁主备切换的问题
2021/04/12 Redis