Objective c 在可变Cocoa对象上实现-hash的技术
Objective c 在可变Cocoa对象上实现-hash的技术,objective-c,cocoa,cocoa-touch,hash,Objective C,Cocoa,Cocoa Touch,Hash,-hash的文档说明,当可变对象存储在集合中时,该值不得更改,类似地,-isEqual:的文档说明,对于相同的对象,-hash的值必须相同 鉴于此,是否有人对实现-hash的最佳方法有任何建议,以使其既满足这两个条件,又能进行智能计算(即不只是返回0)?有人知道框架提供的类的可变版本是如何做到这一点的吗 当然,最简单的方法就是忘记第一个条件(关于它不会改变),确保在对象在集合中时不会意外地改变对象,但我想知道是否有更灵活的解决方案 编辑:我想知道,当我改变对象的内部状态时,是否有可能维护这两个契
-hash
的文档说明,当可变对象存储在集合中时,该值不得更改,类似地,-isEqual:
的文档说明,对于相同的对象,-hash
的值必须相同
鉴于此,是否有人对实现-hash
的最佳方法有任何建议,以使其既满足这两个条件,又能进行智能计算(即不只是返回0
)?有人知道框架提供的类的可变版本是如何做到这一点的吗
当然,最简单的方法就是忘记第一个条件(关于它不会改变),确保在对象在集合中时不会意外地改变对象,但我想知道是否有更灵活的解决方案
编辑:我想知道,当我改变对象的内部状态时,是否有可能维护这两个契约(相同的对象具有相同的哈希,并且当对象在集合中时哈希不会改变)。我倾向于说“不”,除非我做了一些愚蠢的事情,比如总是为散列返回0,但这就是我问这个问题的原因。在Java中,大多数可变类只是不重写,所以默认实现返回一个基于对象地址的值,并且不会更改。这可能与Objective C相同。我对文档的理解是,
散列的可变对象的值可以(也可能应该)在发生变化时改变,但在对象未发生变化时不应该改变。因此,文档中要引用的部分是:“不要修改存储在集合中的对象,因为这会导致它们的散列值更改。”
直接引自:
如果将可变对象添加到
集合,该集合使用哈希值
确定对象在视图中的位置
集合返回的值
对象的哈希方法不能为空
在对象处于活动状态时更改
收集因此,哈希
方法不能依赖于任何
对象的内部状态信息或
您必须确保对象的
内部状态信息不可用
在对象处于活动状态时更改
收藏
(我的重点。)有趣的问题,但我认为你想要的在逻辑上是不可能的。假设你从两个对象开始,A和B。它们都不同,并且它们以不同的哈希代码开始。您可以将两者添加到某个哈希表中。现在,您希望对A进行变异,但无法更改哈希代码,因为它已经在表中。但是,可以通过这样的方式更改A,即它等于()B
在这种情况下,您有两种选择,但两种选择都不起作用:
将A的hashcode更改为等于B.hashcode,这违反了在哈希表中不更改哈希代码的约束
不要更改hashcode,在这种情况下,A.equals(B)但是它们没有相同的hashcode
在我看来,如果不使用常量作为哈希代码,就不可能做到这一点。因为您已经覆盖了-isEqual:要进行基于值的比较,您确定需要使用-hash吗
当然,我猜不出您到底需要它做什么,但是如果您想在不偏离-isEqual:的预期实现的情况下进行基于值的比较,只在哈希相同时返回YES,那么更好的方法可能是模仿NSString的-isEqualToString:,因此,要创建自己的-isEqualToFoo:方法,而不是使用或重写-isEqual:。这里的问题不是如何满足这两个要求,而是应该满足哪一个要求。在苹果的文件中,明确指出:
可变字典可以放在哈希表中,但当它在哈希表中时,您不能更改它
尽管如此,满足哈希的平等性要求似乎更为重要。对象的散列应该始终是检查一个对象是否等于另一个对象的一种方法。如果情况并非如此,那么它就不是真正的哈希函数
为了结束我的回答,我将给出一个好的哈希实现示例。假设您正在对已创建的集合编写-hash
的实现。此集合将NSObjects数组存储为指针。由于所有NSObject都实现了哈希函数,因此可以使用它们的哈希计算集合的哈希:
- (NSUInteger)hash {
NSUInteger theHash = 0;
for (NSObject * aPtr in self) { // fast enumeration
theHash ^= [aPtr hash];
}
return theHash;
}
这样,包含相同指针(顺序相同)的两个集合对象将具有相同的哈希 这个问题的答案和避免许多可可豆错误的关键是:
仔细阅读文档。把每一个单词和标点符号放在一个金色的天平上,称它的重量,因为它是世界上最后一粒小麦
让我们再次阅读文档:
如果将可变对象添加到使用哈希值确定对象在集合中的位置的集合,[…]
(我的重点)
文档的作者,用他/她的永恒智慧来说,这意味着当您实现一个集合(如字典)时,您不应该使用哈希来定位,因为这可能会改变。换句话说,它与在可变Cocoa对象上实现hash没有多大关系(我们都认为它已经实现了,假设文档在提出问题后的最近10年中没有发生变化)
这就是为什么字典总是复制它们的键——这样它们就能保证
哈希值不会改变
然后,您会问这样一个问题:但是,好先生,NSMapTable和类似产品如何处理这个问题
根据文件,答案如下:
“其键或值可以在输入时复制,或者可以使用指针标识进行相等和散列。”
NSMutableString *string = [NSMutableString stringWithString:@"so lets mutate this"];
NSString *originalString = string.copy;
NSMapTable *mutableStrings = [NSMapTable strongToStrongObjectsMapTable];
[mutableStrings setObject:originalString forKey:string];
[string appendString:@" into a larger string"];
if ([mutableStrings objectForKey:string] == nil)
NSLog(@"not found!");
if ([mutableStrings objectForKey:originalString] == nil)
NSLog(@"Not even the original string is found?");
for (NSString *inCollection in mutableStrings)
{
NSLog(@"key '%@' : is '%@' (null)", inCollection, [mutableStrings objectForKey:inCollection]);
}
for (NSString *value in NSAllMapTableValues(mutableStrings))
{
NSLog(@"value exists: %@", value);
}