美文网首页Swift开发那些事
《Swift进阶》学习笔记之 - Hashable协议

《Swift进阶》学习笔记之 - Hashable协议

作者: lexiaoyao20 | 来源:发表于2017-02-10 10:51 被阅读103次

    标准库中所有的基本数据类型都是遵守 Hashable 协议的,它们包括字符串,整数,浮点数以及布尔值。不带有关联值得枚举类型也会自动遵守 Hashable

    Dictionary 要求它的Key类型需要遵守 Hashable协议,如果你想要将自定义类型用作字典的键,那么你必须手动为你的类型添加 Hashable 并满足它,这需要你实现 hashValue 属性。另外,因为 Hashable 本身是对 Equatable 的扩展,因此还需要为你的类型重载 == 运算符。 你的实现必须保证哈希不变原则两个同样的实例(由你实现的 == 定义相同),必须拥有同样的哈希值。不过反过来不必为真:两个相同的哈希值的实例不一定需要相等

    不同的哈希值的数量是有限制,然而很多可以被哈希的类型(比如字符串)的个数是无穷的。哈希值可能重复这一特性,意味着 Dictionary 必须能够处理哈希碰撞。

    优秀哈希算法的第二个特质是它应该很快。如果你的 hashValue 实现要消耗太多时间,那么它很可能会拖慢你的程序,让你从字典的 O(1)特性中得到的好处损失殆尽。

    写一个能同时做到这些要求的哈希算法并不容易。对于一些由本身就是 Hashable 的数据类型组成的类型来说,将成员的哈希值进行 “异或”(XOR) 运算往往是一个不错的起点:

    //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
        }
    }
    

    异或计算方法的一个限制是,这个操作本身是左右对称的(也就是说 a^b == b^a),对于某些数据的哈希计算,这有时会造成不必要的碰撞。你可以添加一个位旋转并混合使用它们来避免这个问题。

    相关文章

      网友评论

        本文标题:《Swift进阶》学习笔记之 - Hashable协议

        本文链接:https://www.haomeiwen.com/subject/ctrgittx.html