注:以下SO问题是相关的,但他们及链接的资源,似乎完全回答我的问题,特别是有关实施平等试验对象的集合 。
- 用于覆盖-isEqual最佳实践:与-hash
- 对可变Cocoa对象实施-hash技术
背景
NSObject的提供的默认的实现-hash
(它返回该实例的地址,例如(NSUInteger)self
)和-isEqual:
返回NO
除非接收器的地址,并且所述参数是相同的)。 这些方法旨在覆盖作为必要的,但文件清楚地表明,你应该同时提供或者两者都不是。 此外,如果-isEqual:
返回YES
两个对象,然后的结果-hash
那些对象必须是相同的。 如果不是这样,当对象应该是相同的问题接踵而至能-例如两个字符串实例为其中-compare:
返回NSOrderedSame
-被添加到可可收集或直接进行比较。
上下文
我开发CHDataStructures.framework ,Objective-C的数据结构的一个开源库。 我已经实现了一些藏品,和我目前正在不断改善和加强其功能。 有一个问题我想添加的功能是比较收藏与另一平等的能力。
而不是只比较内存地址,这些比较应考虑存在于两个集合的对象(包括订购,如果适用)。 这种方法具有在可可相当先例,通常使用一个独立的方法,其中包括以下内容:
-
-[NSArray isEqualToArray:]
-
-[NSDate isEqualToDate:]
-
-[NSDictionary isEqualToDictionary:]
-
-[NSNumber isEqualToNumber:]
-
-[NSSet isEqualToSet:]
-
-[NSString isEqualToString:]
-
-[NSValue isEqualToValue:]
我想我的自定义集合强大的平等的测试,所以他们可以安全地(和可预测)被加入到其他收藏品,并允许其他人(如一个NSSet中)来确定两个集合是否相等/当量/重复。
问题
一个-isEqualTo...:
方法适用于自己的伟大,但定义这些方法的类通常还覆盖-isEqual:
调用[self isEqualTo...:]
如果参数是同一类的(或者子类)作为接收器,或[super isEqual:]
否则。 这意味着类也必须定义-hash
,这样它将返回具有相同内容不同的情况下,相同的值。
此外,苹果的文档-hash
规定了以下内容:(重点煤矿)
“如果一个可变对象被添加到使用的散列值,以确定该对象的集合中的位置的集合,由对象的哈希方法返回的值不能而所述对象是所述集合中的变化。因此, 无论是散列法必须不依赖于任何对象的内部状态信息, 或者您必须确保当对象是集合中的对象的内部状态信息不会改变。因此,例如,一个可变字典可以放在一个哈希表,但你必须而它在那里不改变它。(请注意,它可能很难知道一个给定的对象是否是一个集合中)。”
编辑: 我绝对明白为什么这是必要的,并与推理完全同意-我在这里提到它提供额外的上下文和回避的原因是为了简洁起见情况的话题。
我所有的藏品都是可变的,哈希将不得不考虑至少部分的内容,所以在这里唯一的选择就是认为这是一个编程错误变异储存在另一个集合的集合。 (我的收藏品全部采用NSCopying ,所以喜欢的NSDictionary的集合可以成功地进行复制的钥匙,等使用)
这是有道理的,我来实现-isEqual:
和-hash
,因为(举例来说)我的课可能不知道具体的一个间接用户-isEqualTo...:
方法来调用,甚至照顾两个对象是否实例同一类别。 他们应该能够调用-isEqual:
或-hash
对类型的任何变量id
并获得预期的结果。
不像-isEqual:
它可以访问两个实例进行比较), -hash
必须返回一个结果“盲目地”,与特定的实例中只访问该数据。 因为它无法知道正在使用什么哈希,其结果必然是应该考虑的平等/相同的所有可能的情况一致,且必须始终同意 (编辑:这是通过下面的答案揭穿,也肯定让生活更轻松)。此外,编写好的哈希函数是不平凡-保证唯一性是一个挑战,尤其是当你只有一个NSUInteger(32/64位)在其中表示它。 -isEqual:
问题
- 有没有实现
平等的比较时的最佳实践-hash
的收藏? - 是否有任何特别之处在Objective-C和可可式的集合计划?
- 有没有什么好的方法进行单元测试
-hash
与合理的置信度? - 在实施任何建议
-hash
与同意-isEqual:
包含任意类型的元素集合? 我应该知道什么陷阱? ( 编辑:我首先想到的不是有问题-因为@kperryua指出,“等于-hash
值并不意味着-isEqual:
”。)
编辑: 我应该澄清,我不是困惑如何实现-isEqual:或-isEqualTo ...:用于收藏,这是简单的。 我想,我的困惑主要来自(错误地)以为-hash必须返回如果-isEqual不同的值:返回NO。 做完加密在过去,我在想,对于散列值不同必须是不同的。 但是,下面的答案使我意识到,一个“好”的哈希函数实际上是关于减少桶的碰撞和链接对于使用集合-hash
。 而独特的哈希值是最好,他们不是一个严格的要求。