为了账号安全,请及时绑定邮箱和手机立即绑定

两个 gob 编码器产生不同的结果

两个 gob 编码器产生不同的结果

Go
慕仙森 2022-10-24 08:49:22
......它让我发疯,试图理解我做错了什么!游乐场:https ://go.dev/play/p/ZQP8Y-gwihQ该示例看起来很做作,但它是从出现错误的代码中提取的。在我的代码中,我正在对字节缓冲区进行哈希处理,并希望该过程是可预测的。package mainimport (    "bytes"    "encoding/gob"    "fmt"    "log")type Foo struct {    Bar string    Baz string}func (f *Foo) X() string {    var b bytes.Buffer    s := struct {        Bar string        Baz string    }{        f.Bar,        f.Baz,    }    log.Printf("%v", s)    gob.NewEncoder(&b).Encode(s)    return fmt.Sprintf("%x", b)}func (f *Foo) Y(x string) string {    var b bytes.Buffer    s := struct {        Bar string        Baz string        S   string    }{        f.Bar,        f.Baz,        x,    }    log.Printf("%v", s)    gob.NewEncoder(&b).Encode(s)    return fmt.Sprintf("%x", b)}func main() {    a := &Foo{        Bar: "bar",        Baz: "baz",    }    log.Println(a.X())    log.Println(a.Y("something"))}运行产量:{bar baz}{1cff81030102ff820001020103426172010c00010342617a010c0000000dff820103626172010362617a00 0 0}{bar baz something}{22ff83030102ff840001030103426172010c00010342617a010c00010153010c00000018ff840103626172010362617a0109736f6d657468696e6700 0 0}注释掉log.Println(a.X())产量:{bar baz something}{22ff81030102ff820001030103426172010c00010342617a010c00010153010c00000018ff820103626172010362617a0109736f6d657468696e6700 0 0}我希望这两种编码相同,但它们在我假设对应于字段边界的位置上(可预测地)不同:22ff83 # 81030102ff84 # 820001030103426172010c00010342617a010c00010153010c00000018ff84 # 820103626172010362617a0109736f6d657468696e6700即使细节不同,行为也与我的代码一致。我在每个方法中都创建了一个新的bytes.Bufferand gob.NewEncoder,所以不清楚为什么调用X会改变Y.
查看完整描述

1 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

您缺少的是Encoder实例生成的字节流除了每个状态之外还具有全局Encoder(程序范围)状态。该全局状态由 [注意:此处编辑的短语] 注册和发送类型组成。

当您发送一个类型化的值时,如果该类型在发送之前尚未注册,它将在全局状态下为您注册。这会为该类型分配一个内部数值。见Register(及其同伴RegisterName)。当您调用您的时,它会注册保存在 中X的匿名结构类型。当您调用您的时,它会注册保存在 中的匿名结构类型。它们得到不同的内部类型编号。通过调用,该类型永远不会被注册,并且' 的类型会在第一个可用号码下注册。sXYsYXY

在我的代码中,我正在对字节缓冲区进行散列...

这不是一个好主意,因为现在可能很明显的原因。 但是,如果您以已知的顺序显式注册每种类型,那么您在这里就足够安全了,除非将来的某个版本出于某些(可能是好的)原因更改了线路格式。 糟糕,对此进行测试表明它也无济于事。这是因为即使该类型已注册,它也没有设置传输编号,直到第一次对该类型的值进行编码。因此,您需要对每种类型的值进行编码(并且可以选择丢弃)。

这是一个仔细丢弃编码这两种类型的有效示例,以便注释掉调用对log.Println(a.X())第二个值的编码没有影响。


查看完整回答
反对 回复 2022-10-24
  • 1 回答
  • 0 关注
  • 79 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信