Swift:具有相同属性的不同对象:哈希值

时间:2017-01-18 19:34:11

标签: swift hash

目前我有一个泛型类,我想通过

使这个类的对象可搜索
contains()

这些对象数组的方法,使类符合Hashable协议并为每个对象提供哈希值。现在我的问题是我有完全相同属性的对象,似乎数组无法真正区分它们(我当前的方法是使用其中一个属性的哈希值作为类的哈希值,以及

== <T> (lhs: ClassA<T>, rhs: ClassA<T>) -> Bool

函数通过比较哈希值来完成)。我试图使用像“id”这样的静态属性,但是对于泛型类型,不支持静态属性。

我应该如何定义哈希值,以便仍然可以区分具有相同属性的不同对象?

编辑:我让它直接符合Hashable,因为它也在程序的其他部分用作dict中的键,因为Hashable已经符合Equatable。

2 个答案:

答案 0 :(得分:1)

  

我目前的做法是使用其中一个属性&#39;哈希值为   该类的哈希值,以及

== <T> (lhs: ClassA<T>, rhs: ClassA<T>) -> Bool
     

函数通过比较哈希值

来完成

这不是==hashValue关系如何运作 - 不要这样做。如果你遇到哈希冲突怎么办?具有不同属性的两个不同实例可以比较相等。

您应该实现==实际比较两个实例的属性。如果两个给定的实例具有相同的属性,则==应返回true。如果两个实例的hashValue==相等,则它们应该是等效的。

现在,除非TEquatable,否则您可能无法进行此比较。对此的一个解决方案是不将ClassAEquatable相符,而是仅在==T时重载Equatable,例如:

func == <T : Equatable>(lhs: ClassA<T>, rhs: ClassA<T>) -> Bool {
    // stub: do comparison logic
}

现在,您可以将Sequence的{​​{3}}方法与==重载结合使用,以检查给定实例是否在数组中:

var array = [ClassA("foo")] // assuming ClassA has an init(_: T) and a suitable ==
                            // implementation to compare that value

let someInstanceToFind = ClassA("foo")
print(array.contains { $0 == someInstanceToFind }) // true

如果您希望ClassA拥有hashValue,那么只需撰写一个extensionhashValue定义T Hashable extension ClassA where T : Hashable { var hashValue: Int { return 0 // to do: implement hashValue logic } }

ClassA

不幸的是,这确实意味着HashableT发生时不会明确地符合hashValue - 但它会有==和{{1}实施。如果满足给定的where子句,contains(where:)将允许显式符合协议,但这尚未实现。

如果您需要与Hashable明确一致(例如在SetDictionary键中使用您的类的实例) - 那么一种解决方案是创建包装器类型:

struct HashableClassA<T : Hashable> : Hashable {

    var base: ClassA<T>

    init(_ base: ClassA<T>) {
        self.base = base
    }

    static func ==(lhs: HashableClassA, rhs: HashableClassA) -> Bool {
        return lhs.base == rhs.base
    }

    var hashValue: Int {
        return base.hashValue
    }
}

现在您只需要在ClassA<T>实例中包含HashableClassA个实例,然后再添加到SetDictionary

答案 1 :(得分:0)

刚刚意识到有一种简单的方法来实现

中的Equatable
contains()

方法:使用

return lhs === rhs
<=>在==函数中,以便直接比较对象。它现在以这种方式工作。