Golang Gob编码

2012-08-24 09:47 by 轩脉刃, 5119 阅读, 1 评论, 收藏, 编辑

gob是Golang包自带的一个数据结构序列化的编码/解码工具。编码使用Encoder,解码使用Decoder。一种典型的应用场景就是RPC(remote procedure calls)。

gob和json的pack之类的方法一样,由发送端使用Encoder对数据结构进行编码。在接收端收到消息之后,接收端使用Decoder将序列化的数据变化成本地变量。

有一点需要注意,

发送方的结构和接受方的结构并不需要完全一致

结构体中缺省的字段将不会被发送。而且在接收方,并不需要所有的字段都要有对应的结构属性对应。godoc中的这个例子很形象:

当发送方传递的是struct{A, B int}结构的值的时候,接收方可以允许前9种结构,但是后面4种结构确实不允许的。

个人觉得这种设定是很符合逻辑的:接收端只接受和发送数据“相似”的数据结构。允许模拟相似,但是不允许矛盾。

各个类型的编解码规则

整型:分为sign int和usign int, 其中从上面例子也看到,int和uint是不能互相编解码的。float和int也是不能互相编解码的。

Struct,array,slice是可以被编码的。但是function和channel是不能被编码的。

bool类型是被当作uint来编码的,0是false,2是true。

浮点类型的值都是被当作float64类型的值来编码的

String和[]byte传递是uint(byte个数) + byte[]的形式编码的

Slice和array是按照uint(array个数) + 每个array编码 这样的形式进行编码的

Maps是按照 uint(Map个数) + 键值对 这样的形式进行编码的

Struct 是按照一对对(属性名 + 属性值)来进行编码的。其中属性值是其自己对应的gob编码。前面说过,如果有一个属性值为0或空,则这个属性直接被忽略。每个属性的序号是由编码时候顺 序决定的,从0开始顺序递增。Struct在序列化前会以-1代表序列化的开始,以0代表序列化结束。即Struct的序列化是按照 “-1 (0 属性1名字 属性1值) (1 属性2名字 属性2值) 0 ”来进行编码的。

非常重要的一点:

Struct中的属性应该是public的,即应该是大写字母开头。

这样才能被包外的函数访问!!(谢谢TreapDB提醒)

Gob提供的函数

Encode和Decode

对于Encoder和Decoder可以看这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main
 
import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)
 
type P struct {
    X, Y, Z int
    Name    string
}
 
type Q struct {
    X, Y *int32
    Name string
}
 
func main() {
    var network bytes.Buffer       
    enc := gob.NewEncoder(&network)
    dec := gob.NewDecoder(&network)
    // Encode (send) the value.
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Println(q)
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
 
}

所有Encoder和Decoder的构造函数都有一个io结构,需要制定你将使用哪个io进行编码解码的传输。

这个代码要注意几个地方:

1 P和Q是两个结构体,应该说是“相似”的两个结构体

2 Encode是将结构体传递过来,但是Decode的函数参数却是一个pointer!

这点在godoc中有说:

f e is nil, the value will be discarded. Otherwise, the value underlying e must be a pointer to the correct type for the next data item received.

Decode的参数如果不是nil,那就一定是一个指针了。

3 如果你将Encode传入一个pointer,即

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.
    // Encode (send) the value.
    err := enc.Encode(&P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Println(q)
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
 
 
}

这个function也是没有问题的。

Register和RegisterName

这两个方法是当编解码中有一个字段是interface{}的时候需要对interface{}的可能产生的类型进行注册。具体就看一下下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main
 
import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)
 
type P struct {
    X, Y, Z int
    Name    interface{}
}
 
type Q struct {
    X, Y *int32
    Name interface{}
}
 
type Inner struct {
    Test int
}
 
func main() {
    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.
     
    gob.Register(Inner{})
     
    // Encode (send) the value.
    inner := Inner{1}
    err := enc.Encode(P{1,2,3, inner})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Println(q)
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
 
 
}

这里使用了gob.Register(Inner{})告诉系统:所有的Interface是有可能为Inner结构的。

在这个例子中,如果你注释了gob.Register, 系统会报错。

RegisterName是和Register一样的效果,只是在Register的同时也为这个类型附上一个别名。

GebEncoder和GobDecoder

这是两个接口,如果你的数据结构实现了这两个接口,当调用encoder.Encode和decoder.Decode的时候就会调用这两个结构的对应函数

看一下下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main
 
import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)
 
type P struct {
    X, Y, Z int
    Name    string
}
 
func (this *P)GobEncode() ([]byte, error) {
    return []byte{},nil
}
 
type Q struct {
    X, Y *int32
    Name string
}
 
func main() {
    var network bytes.Buffer       
    enc := gob.NewEncoder(&network)
    dec := gob.NewDecoder(&network)
    // Encode (send) the value.
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Println(q)
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
 
}

这里我的P实现了GobEncoder接口,因此在enc.Encode的时候会调用func (this *P)GobEncode() ([]byte, error)

当然我这个函数直接返回的是空byte,因此在解码的时候会报错:decode error:gob: type mismatch in decoder: want struct type main.Q; got non-struct

这两个接口暴露出来就代表你为自己定义的结构进行编解码规则制定。当然,如果使用自己的编解码规则,在编码和解码的过程就需要是一对的

[转]Golang Gob编码的更多相关文章

  1. golang - gob与rpc

    今天和大家聊聊golang中怎么使用rpc,rpc数据传输会涉及到gob编码,所以先讲讲gob,别担心,就算你完全没有接触过gob与rpc,只要知道rpc的中文是远程过程调用,剩下的我都能给你讲明白( ...

  2. golang gob 有什么优势? gob/protobuf/json/xml 效率对比,benchmark 压力测试

    TODO 待研究: https://blog.csdn.net/love_se/article/details/7941876 https://blog.csdn.net/wangshubo1989/ ...

  3. golang json 编码解码

    json 编码 package main import ( "encoding/json" "fmt" ) type Person struct { Name ...

  4. Golang 字符编码

    需要添加的库 go get code.google.com/p/go.text/encoding go get code.google.com/p/go.text/transform 两个转码函数 i ...

  5. golang rpc demo

    RPC工作流程图 1.调用客户端句柄:执行传送参数 2.调用本地系统内核发送网络消息 3.消息传送到远程主机 4.服务器句柄得到消息并取得参数 5.执行远程过程 6.执行的过程将结果返回服务器句柄 7 ...

  6. golang编码转换

    在网上搜索golang编码转化时,我们经常看到的文章是使用下面一些第三方库: https://github.com/djimenez/iconv-go https://github.com/qiniu ...

  7. golang 编码转化

    在网上搜索golang编码转化时,我们经常看到的文章是使用下面一些第三方库: https://github.com/djimenez/iconv-go https://github.com/qiniu ...

  8. 转: gob编解码

    要让数据对象能在网络上传输或存储,我们需要进行编码和解码.现在比较流行的编码方式有JSON,XML等.然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON.gob是Golang包 ...

  9. golang中的rpc开发

    golang中实现RPC非常简单,官方提供了封装好的库,还有一些第三方的库 golang官方的net/rpc库使用encoding/gob进行编解码,支持tcp和http数据传输方式,由于其他语言不支 ...

随机推荐

  1. 递归算法(一)——akm

    要求 已知akm函数如下: { n+1 while m=0 }                          => Rule I akm(m,n)= { akm(m-1,1) while n ...

  2. Objective-C:Foundation框架-概述

    iOS的整体架构(以iOS8为例)图如下: 从Cocoa Touch到Core OS下面四层包含了开发iOS应用程序所用到的所有API(第三方框架也是基于这几个层的).每个层又都包含了许多框架.框架就 ...

  3. Linux下smba服务端的搭建和客户端的使用

    解决了 windows下用root登录linuxsamba后有部分目录访问无权限的问题.应该是SELinux 设置问题. 对selinux进行修改,一般为终止这项服务,操作如下: 查看SELinux状 ...

  4. kindeditor 操作时同步到textarea

    KindEditor.ready(function(K) { editor1 = K.create('textarea[name="sponsor"]', { resizeType ...

  5. Struts+Spring+Hibernate整合入门详解

    Java 5.0 Struts 2.0.9 Spring 2.0.6 Hibernate 3.2.4 作者:  Liu Liu 转载请注明出处 基本概念和典型实用例子. 一.基本概念       St ...

  6. NDK JNI 的关键点

    1.System.loadLibrary 的名字是在Android.mk里面设定的   LOCAL_MODULE    := httpdown,MODULE   后面跟的就是了 2.如何正确调用到关键 ...

  7. Zabbix源码包安装

    Zabbix源码包安装 Cenos5.3 Basic server 安装顺序 Libxml2 Libmcrypt Zlib Libpng Jpeg:需要创建目录jpeg  /bin  /lib   / ...

  8. 初步比较zeromq vs. wcf

    用最简单的Calculator比较zeromq的req-rep模式 vs. wcf的http和net.tcp模式,看哪一种的传输性能更高. 1.比较结果如下 方式 耗费时间 wcf_http_sing ...

  9. redis学习(一)

    一.redis简介 Redis是基于内存.可持久化的日志型.key-value高性能存储系统.关键字(Keys)是用来标识数据块.值(Values)是关联于关键字的实际值,可以是任何东西.有时候你会存 ...

  10. AOP面向切面编程

    1.AOP Aop(aspect object programming)面向切面编程 功能: 让关注点代码与业务代码分离! 关注点 重复代码就叫做关注点: 切面 关注点形成的类,就叫切面(类)! 面向 ...