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. JavaScript第一部分

    一.JavaScript简介 1.JavaScript是个什么东西? 它是个脚本语言,需要有宿主文件,它的宿主文件是HTML文件. 2.它与Java什么关系? 没有什么直接的联系,Java是Sun公司 ...

  2. Java--常用类summary

    /* 2:API的概述(了解) (1)应用程序编程接口. (2)就是JDK提供给我们的一些提高编程效率的java类. 3:Object类(掌握) (1)Object是类层次结构的根类,所有的类都直接或 ...

  3. 用c#开发苹果应用程序 xamarin.ios方式

    NetworkComms网络通信框架序言 Networkcomms网络通信框架来自于英国,支持以xamarin.ios的方式开发苹果应用程序 其开源版本2.3.1中带有一个示例程序,实现聊天功能,只要 ...

  4. php验证用户名是否以字母开头与验证密码

    验证用户名是否以字母开头与验证密码只能为数字和字母的组合代码三款三种常用验证函数 验证邮箱地址格式  验证密码只能为数字和字母的组合 验证用户名是否以字母开头代码哦,这是用户注册时或提交表单时会用的哦 ...

  5. The Python web services developer: XML-RPC for Python

    原文地址:http://www.ibm.com/developerworks/webservices/library/ws-pyth10/index.html 摘要:概括地说,您可以将 XML-RPC ...

  6. hduacm 3183 rmq

    http://acm.hdu.edu.cn/showproblem.php?pid=3183 问题等价与取N-M个数,每次取的时候保证后面能取的个数足够,并且取的数最小  查询最小用rmq #incl ...

  7. webApi跨域

    <system.webServer> <httpProtocol> <customHeaders> <add name="Access-Contro ...

  8. IPTables系列:如何配置Ubuntu 14.04中的IPTables防火墙

    IPTables基本命令 在向大家介绍复杂防火墙规则之前,还是先上一些简单的料,让大家对IPTables最为基本的命令有一些简单了解. 首先要说明的是IPTables命令必需以root权限运行,这意味 ...

  9. u-boot 之配置分析 (2)

    Makefile简要分析所有这些目录的编译连接都是由顶层目录的makefile来确定的. 1.在makefile中有: unconfig: @rm -f $(obj)include/config.h ...

  10. Java爬虫,信息抓取的实现

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/23272657 今天公司有个需求,需要做一些指定网站查询后的数据的抓取,于是花了点 ...