首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编码/gob是确定性的吗?

编码/gob是确定性的吗?
EN

Stack Overflow用户
提问于 2015-10-20 05:31:03
回答 3查看 1.6K关注 0票数 9

对于两个Go对象x,y,使得x等于y(假设不存在接口和映射的复杂性,只是结构和数组),那么gob_encode(x)和gob_encode(y)的输出总是相同的吗?

编辑(2018年6月8日):

当涉及到non-deterministic映射时,gob编码是。这是由于映射的随机迭代顺序,导致它们的序列化被随机排序。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-20 05:45:32

你不应该真的关心它,只要它“完成工作”。但是当前的encoding/gob实现是确定性的。但是(继续读)!

因为:

一股采空区是自我描述的。流中的每个数据项前面都有其类型的规范,表示为一组预定义的类型。

这意味着,如果您第一次编码一个类型的值,类型信息将被发送。如果对同一类型的另一个值进行编码,类型说明将不再传输,只是对其先前规范的引用。因此,即使对相同的值编码两次,它也会产生不同的字节序列,因为第一个字节序列将包含类型规范和值,第二个字节序列将只包含类型ref (例如id类型)和值。

参见此示例:

代码语言:javascript
复制
type Int struct{ X int }

b := &bytes.Buffer{}
e := gob.NewEncoder(b)

e.Encode(Int{1})
fmt.Println(b.Bytes())

e.Encode(Int{1})
fmt.Println(b.Bytes())

e.Encode(Int{1})
fmt.Println(b.Bytes())

输出(在围棋游乐场上尝试):

代码语言:javascript
复制
[23 255 129 3 1 1 3 73 110 116 1 255 130 0 1 1 1 1 88 1 4 0 0 0 5 255 130 1 2 0]
[23 255 129 3 1 1 3 73 110 116 1 255 130 0 1 1 1 1 88 1 4 0 0 0 5 255 130 1 2 0 5 255 130 1 2 0]
[23 255 129 3 1 1 3 73 110 116 1 255 130 0 1 1 1 1 88 1 4 0 0 0 5 255 130 1 2 0 5 255 130 1 2 0 5 255 130 1 2 0]

正如第一个Encode()生成大量字节加上Int值为[5 255 130 1 2 0]的值一样,第二个和第三个调用添加了相同的[5 255 130 1 2 0]序列。

但是,如果您创建了两个不同的gob.Encoder,并且按照相同的顺序编写相同的值,它们将产生精确的结果。

注意,在前面的语句中,“相同的顺序”也很重要。由于在发送该类型的第一个值时发送类型规范,以不同顺序发送不同类型的值也将以不同的顺序发送类型规格,因此类型的引用/标识符可能有所不同,这意味着当对该类型的值进行编码时,将使用/发送不同类型的引用/id。

还要注意的是,gob包的实现可能会在不同版本之间发生变化。这些更改将是向后兼容的(如果出于某种原因,它们必须显式声明是否会进行向后不兼容的更改),但向后兼容并不意味着输出是相同的。因此,不同的Go版本可能会产生不同的结果(但是所有版本都是可解码的,所有兼容版本都是可解码的)。

票数 9
EN

Stack Overflow用户

发布于 2018-06-07 04:59:02

应该注意的是,接受的答案是不正确的:编码/gob不以确定的方式排列map元素:5Kb3Znn

在将映射写入流之前,我对编码/gob进行了分叉处理,并添加了一些代码来按键对映射进行排序。这将影响性能,但我的特定应用程序不需要高性能。请记住,自定义编组程序可能会破坏这一点,因此请小心使用:https://github.com/dave/stablegob

票数 4
EN

Stack Overflow用户

发布于 2020-10-26 11:23:51

如果您使用不同的类型和不同的编码器,它也不是确定性的。

示例:

代码语言:javascript
复制
package main

import (
    "bytes"
    "crypto/sha1"
    "encoding/gob"
    "encoding/hex"
    "log"
)

func main() {
    encint()
    encint64()
    encstring()

}

func encint() {
    s1 := []int{0, 2, 4, 5, 7}
    buf2 := bytes.Buffer{}
    enc2 := gob.NewEncoder(&buf2)
    enc2.Encode(s1)
}

func encint64() {
    s1 := []int64{0, 2, 4, 5, 7}
    buf2 := bytes.Buffer{}
    enc2 := gob.NewEncoder(&buf2)
    enc2.Encode(s1)
}

func encstring() {
    s1 := []string{"a", "b", "c", "d"}
    buf2 := bytes.Buffer{}
    enc2 := gob.NewEncoder(&buf2)
    enc2.Encode(s1)
    log.Println(buf2.Bytes())

    hash := sha1.New()
    hash.Write(buf2.Bytes())
    ret := hash.Sum(nil)
    log.Println(hex.EncodeToString(ret))
}

围棋游乐场中运行

注意,如果您注释掉encint()encint64()encstring将生成不同的字节和不同的哈希代码。

尽管使用了不同的对象/指针,但还是会发生这种情况。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33228700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档