go 自己实现一个gob编解码
2017-03-10 16:56
351 查看
代码库
比如如下代码:
使用gob是无法对上面的in进行正确编解码的,为了解决上面的问题,所以我需要自己实现一个可以完美支持任意内置类型的interface{}的编码系统
这样就可以在解析的时候,根据对应的类型ID生成值并且解析值。
因为需要自动生成类型ID的值,所以对于自定义类型我们需要进行注册。目前只支持自定义的结构体注册。
可以编解码任意的内置类型的slice map。
类型ID由structID、指针深度、reflect.kind三部分拼接而成,
其中structID在注册struct类型的时候分配
2.
由多个类型ID拼接而成,目前为了适应[]interface{}的类型,还对每一个element也进行了类型+值的编码,可以考虑非[]interface{}类型,则只在头部编码element类型即可
3.
map的类型ID和slice差不多
4.
5.多层嵌套类型
则是elementid又是一个slice之类 按照上面的模式先嵌套玩类型即可如:
对于array,len是属于type的一部分,因此在嵌套的时候会现有len
为什么要写这么一个编解码
golang内部也实现了一个gob的二进制编解码,接口简单,使用方便,但是它对interface的支持不是很好,比如如下代码:
var in []interface{} = []interface{}{1, 1.5, "abc", "123", map[int]int{1: 1, 2: 2, 3: 3}} enc.Encode(in) var out []interface{} dec.Decode(&out) fmt.Println(out)
使用gob是无法对上面的in进行正确编解码的,为了解决上面的问题,所以我需要自己实现一个可以完美支持任意内置类型的interface{}的编码系统
想法
为了达到这样的目的,我们需要将每一个interface的类型ID和值编码都编码进二进制流中.这样就可以在解析的时候,根据对应的类型ID生成值并且解析值。
因为需要自动生成类型ID的值,所以对于自定义类型我们需要进行注册。目前只支持自定义的结构体注册。
使用
package gob_test import "github.com/sydnash/lotou/encoding/gob" import "fmt" import "testing" import "reflect" func TestType(t *testing.T) { enc := gob.NewEncoder() a := make([]interface{}, 0, 10) a = append(a, int(-5)) a = append(a, int8(-1)) a = append(a, int16(-2)) a = append(a, int32(-3)) a = append(a, int64(-4)) a = append(a, uint(6)) a = append(a, uint8(7)) a = append(a, uint16(8)) a = append(a, uint32(9)) a = append(a, uint64(10)) a = append(a, float32(0.99999)) a = append(a, float64(0.9999999999)) a = append(a, "this is a string") a = append(a, "这也是一个string") a = append(a, &gob.T1{10, "哈哈,这都可以?", 1.5, -100}) a = append(a, &gob.T2{gob.T1{10, "哈哈,这都可以?", 1.5, -100}, "那么这样还可以吗?"}) a = append(a, gob.T1{10, "哈哈,这都可以?", 1.5, -100}) a = append(a, gob.T2{gob.T1{10, "哈哈,这都可以?", 1.5, -100}, "那么这样还可以吗?"}) a = append(a, true) a = append(a, false) a = append(a, [3]int{1, 2, 3}) a = append(a, []byte{}) m := make(map[int]string) m[1] = "map的第一个元素" m[1] = "map的第二个元素" a = append(a, m) s := make([]string, 0, 2) s = append(s, "这是slice的元素") a = append(a, s) str := "这是一个[]byte" s1 := []byte(str) a = append(a, s1) b := make([]interface{}, 0, 10) b = append(b, m) b = append(b, s) b = append(b, s1) a = append(a, b) a = append(a, a) //start encode for _, v := range a { enc.Encode(v) } //create decoder dec := gob.NewDecoder() dec.SetBuffer(enc.Buffer()) var ok bool = true var r interface{} idx := 0 for ok { //decode r, ok = dec.Decode() fmt.Println(r, reflect.TypeOf(r), ok) if ok { //check decode is ok? if !reflect.DeepEqual(r, a[idx]) { t.Errorf("%v is not equal to %v at idx %v", r, a[idx], idx) } if reflect.TypeOf(r) != reflect.TypeOf(a[idx]) { t.Errorf("%v is not equal to %v at idx %v", reflect.TypeOf(r), reflect.TypeOf(a[idx]), idx) } idx++ } } }
可以编解码任意的内置类型的slice map。
主要实现
类型编码
基本类型编码类型ID由structID、指针深度、reflect.kind三部分拼接而成,
func gernerateId(kind, depth, structId uint) uint16 { id := uint16(structId)<<8 | uint16(depth)<<5 | uint16(kind) return id }
其中structID在注册struct类型的时候分配
2.
slice
由多个类型ID拼接而成,目前为了适应[]interface{}的类型,还对每一个element也进行了类型+值的编码,可以考虑非[]interface{}类型,则只在头部编码element类型即可
sliceid elementid len elementid elementvalue elementid elementvalue ...
3.
map
map的类型ID和slice差不多
mapid keyid eleid len keyid keyvalue eleid elevalue ...
4.
array
arrayid keyid len eleid elevalue ...
5.多层嵌套类型
则是elementid又是一个slice之类 按照上面的模式先嵌套玩类型即可如:
sliceid sliceid elementid[][]int
mapid elementid sliceid elementidmap[int][]int
对于array,len是属于type的一部分,因此在嵌套的时候会现有len
arrayid arrayid elementid len len
sliceid arrayid elmid len len
解码和创建
在解析出来类型id之后,通过一个预定义的map映射到reflect.type上,然后通过reflect.new函数来创建对应的类型的值,最终通过reflect.Value.interface返回为相关文章推荐
- Go实战--实现一个自己的网络请求日志httplogger(The way to go)
- 自己实现的一个分页-用户控件
- 自己写的一个用AJAX实现的留言系统
- 自己实现一个数据库连接池
- 自己编写的一个Json工具类,实现了反射将整个Object转换为Json对象的功能,支持Hibernate的延迟加载对象[修订081217]
- 自己实现一个数据库连接池
- 自己实现的一个Script Callback
- 发一个自己用JS写的实用看图工具实现代码
- 自己实现一个数据库连接池
- 自己实现一个“线程池”
- 自己编写的一个Json工具类,实现了反射将整个Object转换为Json对象的功能,支持Hibernate的延迟加载对象
- 自己实现一个“线程池”zz
- 给自己的网站制作一个favicon.ico图标的实现方法
- 自己实现一个数据库连接池
- 自己实现一个数据库连接池
- 自己实现一个release版的TRACE
- 自己实现一个数据库连接池
- 自己写了一个上传类,实现了常用的功能
- 自己实现一个数据库连接池
- 自己编写的一个Json工具类,实现了反射将整个Object转换为Json对象的功能,支持Hibernate的延迟加载对象