【问题标题】:Swift: different objects with same properties: hash valueSwift:具有相同属性的不同对象:哈希值
【发布时间】:2017-01-18 19:34:11
【问题描述】:

目前我有一个泛型类,我想让这个类的对象可以通过

搜索
contains()

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

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

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

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

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

【问题讨论】:

  • 如果您希望两个具有相同属性的不同对象不相等,您可以添加一个标识符(例如,新对象的自动递增 id)来区分它们或只使用它们的指针值(对于类类型)。

标签: swift hash


【解决方案1】:

我目前的方法是使用其中一个属性的哈希值作为 类的哈希值,以及

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

功能是通过比较哈希值来完成的

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

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

现在,除非TEquatable,否则您可能无法进行此比较。一种解决方案是不将ClassAEquatable 一致,而是在TEquatable 时重载==,例如:

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

您现在可以将Sequencecontains(where:) 方法与== 重载结合使用,以检查给定实例是否在数组中:

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,那么只需编写一个extension,当THashable 时定义一个hashValue

extension ClassA where T : Hashable {
    var hashValue: Int {
        return 0 // to do: implement hashValue logic
    }
}

不幸的是,这确实意味着ClassA 不会明确地符合Hashable,而T 确实如此——但它会有hashValue== 实现。如果满足给定的where 子句,SE-0143: Conditional conformances 将通过允许显式遵守协议来改变这一点,但这尚未实现。

如果您需要明确符合 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&lt;T&gt; 实例包装在HashableClassA 实例中,然后再添加到SetDictionary

【讨论】:

    【解决方案2】:

    刚刚意识到有一种简单的方法可以在

    中实现 Equatable
    contains()
    

    方法:使用

    return lhs === rhs
    

    在 == 函数中直接比较对象。它现在以这种方式工作。

    【讨论】:

    • 请注意,这可能会导致两个不同实例的结果令人惊讶/i> 实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    • 2011-05-04
    • 2013-04-30
    • 2018-11-13
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多