亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

編碼/gob 是確定性的嗎?

編碼/gob 是確定性的嗎?

Go
陪伴而非守候 2021-11-15 20:33:02
我們是否可以期望兩個 Go 對象 x, y 使得 x 等于 y(假設沒有接口和映射的技巧,只有結構和數組)gob_encode(x) 和 gob_encode(y) 的輸出將始終相同?edit (Jun 8 2018):當涉及地圖時,gob 編碼是不確定的。這是由于地圖的隨機迭代順序,導致它們的序列化是隨機排序的。
查看完整描述

3 回答

?
紅顏莎娜

TA貢獻1842條經驗 獲得超13個贊

只要它“完成工作”,您就不應該真正在意。但是當前的encoding/gob實現是確定性的。但是(繼續閱讀)!


自從:


一連串的gobs是不言自明的。流中的每個數據項前面都有其類型的規范,以一小組預定義類型表示。


這意味著如果您第一次對某個類型的值進行編碼,則會發送類型信息。如果您對相同類型的另一個值進行編碼,則不會再次傳輸類型描述,只是對其先前規范的引用。因此,即使您對相同的值進行兩次編碼,它也會產生不同的字節序列,因為第一個將包含類型規范和值,第二個將僅包含一個類型 ref(例如類型 id)和值。


看這個例子:


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())

輸出(在Go Playground上試試):


[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]序列。


但是,如果您創建 2 個不同的gob.Encoders 并以相同的順序寫入相同的值,它們將產生精確的結果。


請注意,在前面的語句中“相同順序”也很重要。因為類型說明是在發送這種類型的第一個值時傳輸的,所以不同類型的值以不同的順序發送也會以不同的順序傳輸類型說明,因此類型的引用/標識符可能不同,這意味著當一個值此類類型已編碼,將使用/發送不同類型的引用/ID。


另請注意,gob包的實現可能會因發行版而異。這些更改將向后兼容(他們必須明確說明是否出于某種原因會進行向后不兼容的更改),但向后兼容并不意味著輸出是相同的。所以不同的 Go 版本可能會產生不同的結果(但所有兼容版本都可以解碼)。


查看完整回答
反對 回復 2021-11-15
?
慕哥9229398

TA貢獻1877條經驗 獲得超6個贊

可能應該注意的是,接受的答案是不正確的:編碼/gob 不會以確定性的方式對地圖元素進行排序:https : //play.golang.org/p/Hh3_5Kb3Znn

我已經分叉了 encoding/gob 并添加了一些代碼以在將它們寫入流之前按鍵對地圖進行排序。這會影響性能,但我的特定應用程序不需要高性能。請記住自定義封送拆收器可以打破這一點,所以小心使用:https : //github.com/dave/stablegob


查看完整回答
反對 回復 2021-11-15
?
米琪卡哇伊

TA貢獻1998條經驗 獲得超6個贊

如果您使用不同的類型和不同的編碼器,它也不是確定性的。


例子:


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))

}

在Go Playground 中奔跑


請注意,如果你注釋掉encint()或者encint64()在encstring會產生不同的字節和不同的哈希碼。


盡管使用了不同的對象/指針,但還是會發生這種情況。


查看完整回答
反對 回復 2021-11-15
  • 3 回答
  • 0 關注
  • 260 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號