Go的Gob包是一个专职于Go语言的高效,易用的编码系统,用于传输数据的包
1. 概述
要通过网络传输数据结构或将其存储在文件中,必须对其进行编码然后再次解码。当然有很多可用的编码:JSON,XML,Google的协议缓冲区(protocol buffers)等等。
现在还有另一个,由Go的gob包提供。为何需要gob包?
因为对于特定于Go的环境,例如在使用Go编写的两个服务器之间进行通信,则有机会构建更多内容更容易使用,可能更有效。
2. gob的主要目标
- 易于使用:gobs永远不会与其他语言一起使用;因为Go有反射,所以不需要单独的接口定义语言或“协议编译器”;
- 传输效率:以XML和JSON为例的文本表示太慢,无法置于高效通信网络的中心。二进制编码是必要的;
- Gob流必须是自我描述的:即使在您忘记它代表的数据之后很久,也始终能够解码存储在文件中的gob流;
3. Pbf的功能缺陷
协议缓冲区对gob的设计有重大影响,但有三个特意被故意避免。(不考虑协议缓冲区不是自描述的属性:如果您不知道用于编码协议缓冲区的数据定义,则可能无法解析它。)
- 首先,协议缓冲区仅适用于我们在Go中称为结构的数据类型。(Pbf您不能在顶层编码整数或数组,只能将其放入到对应的包含字段的结构。)
- 其次,协议缓冲器定义可以指定每当编码或解码类型T的值时都需要存在字段T.x和T.y。(它们也是一个维护问题。随着时间的推移,人们可能希望修改数据定义以删除必填字段,但这可能会导致数据的现有客户端崩溃。)
- 再次,是默认值问题。(Pbf的默认值增加了设计和实现的复杂性,Gob基于Go的默认值规则,它具有该类型的“零值” - 并且它不需要传输
所以gob最终看起来像一种通用的,简化的协议缓冲区。
4. gob值 - 忽略零值,类型可变
gob值类似于go中的常量,对于类似int8和int16没有做区分,同样针对有符合和无符号也未做区分,比如值7,字节传输过程中的值有符号和无符号被相同的传递,接收值针对值进行解码操作,因此编码的值可能是int8类型,接收值类型变为int64。这个值是一个整数,只要它适合,一切都有效(不适合转换的会报错),这种与变量大小的分离为编码提供了一些灵活性:我们可以随着软件的发展扩展整数变量的类型,但仍然能够解码旧数据。
这种灵活性也适用于指针。比如int8, *int8, **int8, ****int8
|
|
从整数我们可以构建所有其他类型:字节,字符串,数组,切片,映射,甚至浮点数。浮点值由它们的IEEE 754浮点位模式表示,存储为整数,只要您知道它们的类型就可以正常工作,我们总是这样做。顺便说一句,该整数以字节反转顺序发送,因为浮点数的常见值(如小整数)在低端有很多零,我们可以避免传输。
Go使得gobs的一个很好的特性是它们允许你通过让你的类型满足GobEncoder
和GobDecoder
接口来定义自己的编码,类似于JSON包的Marshaler
和Unmarshaler
,以及来自包fmt的Stringer
接口。此工具可以在传输数据时表示特殊功能,强制执行约束或隐藏机密。
5. gob类型底层实现 - 首次传递包含类型描述,后续基于类型编码ID
第一次发送给定类型时,gob包在数据流中包含该类型的描述。实际上,所发生的是编码器用于以标准gob编码格式编码描述类型的内部结构并为其提供唯一编号。 (基本类型,以及类型描述结构的布局,由软件预定义用于自举。)在描述类型之后,可以通过其类型编号引用它。
因此,当我们发送第一个类型T时,gob编码器发送T的描述并用类型编号标记它,比如127.所有值(包括第一个)都以该数字为前缀,因此T值流看起来像:
|
|
6. 编译机器 - 利用Go的反射构造
6.1. 编码
第一次编码给定类型的值时,gob包会构建一个特定于该数据类型的解释机器。
gob包使用类型的反射来构造该机器,但是一旦机器被构建,它就不依赖于反射。
该机器使用包不安全和一些技巧将数据高速转换为编码字节。它可以使用反射并避免不安全,但会明显变慢。 (Go的协议缓冲支持采用了类似的高速方法,其设计受到gob实现的影响。)
相同类型的后续值使用已编译的机器,因此可以立即对它们进行编码。
6.2. 解码
解码类似但更难。解码值时,gob包保存一个字节切片,表示要解码的给定编码器定义类型的值,以及要对其进行解码的Go值。
gob包为这一对构建了一台机器:在线上发送的gob类型与提供解码的Go类型交叉。然而,一旦构建了解码机,它又是一个无反射的引擎,它使用不安全的方法来获得最大速度。
7. gob使用 - 高效,易用的编码系统,用于传输数据。
利用gob传输数据,需要做的就是为gob包提供值和变量,它可以完成所有的工作。
|
|
8. 应用 - go的rpc包
pc软件包构建在gobs之上,可将此编码/解码自动化转换为传输,以便通过网络进行方法调用。