......它讓我發瘋,試圖理解我做錯了什么!游樂場: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
的匿名結構類型。當您調用您的時,它會注冊保存在 中的匿名結構類型。它們得到不同的內部類型編號。通過不調用,該類型永遠不會被注冊,并且' 的類型會在第一個可用號碼下注冊。s
X
Y
s
Y
X
Y
在我的代碼中,我正在對字節緩沖區進行散列...
這不是一個好主意,因為現在可能很明顯的原因。 但是,如果您以已知的順序顯式注冊每種類型,那么您在這里就足夠安全了,除非將來的某個版本出于某些(可能是好的)原因更改了線路格式。 糟糕,對此進行測試表明它也無濟于事。這是因為即使該類型已注冊,它也沒有設置傳輸編號,直到第一次對該類型的值進行編碼。因此,您需要對每種類型的值進行編碼(并且可以選擇丟棄)。
這是一個仔細丟棄編碼這兩種類型的有效示例,以便注釋掉調用對log.Println(a.X())
第二個值的編碼沒有影響。
- 1 回答
- 0 關注
- 143 瀏覽
添加回答
舉報
0/150
提交
取消