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. (转载整理)SAP ERP常用表

    abap 常用表 GL部分:FAGLFLEXT(FMGLFLEXT)   新总账汇总表 GLT0        旧总帐汇总表           SKA1        总账科目主记录 (科目表)   ...

  2. MATLAB随机森林回归模型

    MATLAB随机森林回归模型: 调用matlab自带的TreeBagger.m T=textread('E:\datasets-orreview\discretized-regression\10bi ...

  3. js基础练习---图片无缝左右滚动效果(主要以复制删除为主)

    昨天闲来没事 看了下图片效果  发现这个方法j 就自己模仿下 上代码  当中有很多的纰漏 请大神们多多指教一二? <script type="text/javascript" ...

  4. Oracle存储过程写法

    create or replace procedure QIANFEIGL_JIAOKUANDY( cebenh varchar2, kehuh varchar2, hetongh varchar2, ...

  5. 推荐cms

    推荐cms : 国外:drupal  joomla wordpress 国内:phpcms

  6. 使用SoundPool播放音效

    针对应用程序经常需要播放密集.短促的音效,因为MediaPlayer存在如下缺点: 1.资源占用量较高.延迟时间较长. 2.不支持多个音效同时播放. SoundPool使用音效池的概念来管理多个短促的 ...

  7. c# 调用 ShellExecute

    using System.Runtime.InteropServices; namespace ConsoleTest{    class Program    {        public enu ...

  8. C#winform省市县联动,以及有的县是空值时显示异常的处理

    一.如下comboBox1.comboBox2.comboBox3,原来这三个都是空的, 将数据库中的省份传递到comboBox1中 我的数据库有parent字段,根据市的parent找到省,根据县的 ...

  9. .className = "highlight";.setAttribute("class", "highlight");

    document.getElementById("top").innerHTML = newHTML; document.getElementById("contact& ...

  10. 阿里公共DNS 正式发布了

    喜大普奔!集阿里巴巴集团众多优秀工程师开发维护的公共DNS---AliDNS终于上线啦!作为国内最大的互联网基础服务提供商,阿里巴巴在继承多年优秀技术的基础上,通过提供性能优异的公共DNS服务,为广大 ...