《Swift進(jìn)階》學(xué)習(xí)筆記之 - Hashable協(xié)議

標(biāo)準(zhǔn)庫中所有的基本數(shù)據(jù)類型都是遵守 Hashable 協(xié)議的,它們包括字符串,整數(shù),浮點(diǎn)數(shù)以及布爾值。不帶有關(guān)聯(lián)值得枚舉類型也會(huì)自動(dòng)遵守 Hashable。

Dictionary 要求它的Key類型需要遵守 Hashable協(xié)議,如果你想要將自定義類型用作字典的鍵,那么你必須手動(dòng)為你的類型添加 Hashable 并滿足它,這需要你實(shí)現(xiàn) hashValue 屬性。另外,因?yàn)?Hashable 本身是對(duì) Equatable 的擴(kuò)展,因此還需要為你的類型重載 == 運(yùn)算符。 你的實(shí)現(xiàn)必須保證哈希不變?cè)瓌t兩個(gè)同樣的實(shí)例(由你實(shí)現(xiàn)的 == 定義相同),必須擁有同樣的哈希值。不過反過來不必為真:兩個(gè)相同的哈希值的實(shí)例不一定需要相等。

不同的哈希值的數(shù)量是有限制,然而很多可以被哈希的類型(比如字符串)的個(gè)數(shù)是無窮的。哈希值可能重復(fù)這一特性,意味著 Dictionary 必須能夠處理哈希碰撞。

優(yōu)秀哈希算法的第二個(gè)特質(zhì)是它應(yīng)該很快。如果你的 hashValue 實(shí)現(xiàn)要消耗太多時(shí)間,那么它很可能會(huì)拖慢你的程序,讓你從字典的 O(1)特性中得到的好處損失殆盡。

寫一個(gè)能同時(shí)做到這些要求的哈希算法并不容易。對(duì)于一些由本身就是 Hashable 的數(shù)據(jù)類型組成的類型來說,將成員的哈希值進(jìn)行 “異或”(XOR) 運(yùn)算往往是一個(gè)不錯(cuò)的起點(diǎn):

//Hashable 要求
struct Person {
    var name: String
    var zipCode: Int
    var birthday: Date
}

extension Person: Equatable {
    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
            && lhs.zipCode == rhs.zipCode
            && lhs.birthday == rhs.birthday
    }
}

extension Person: Hashable {
    var hashValue: Int {
        return name.hashValue ^ zipCode.hashValue ^ birthday.hashValue
    }
}

異或計(jì)算方法的一個(gè)限制是,這個(gè)操作本身是左右對(duì)稱的(也就是說 a^b == b^a),對(duì)于某些數(shù)據(jù)的哈希計(jì)算,這有時(shí)會(huì)造成不必要的碰撞。你可以添加一個(gè)位旋轉(zhuǎn)并混合使用它們來避免這個(gè)問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容