1. ホーム
  2. オブジェクティブC

[解決済み】isEqual:とハッシュをオーバーライドするためのベストプラクティス

2022-04-04 17:59:10

質問

を正しくオーバーライドするにはどうすればよいのでしょうか? isEqual: Objective-Cでは? 2つのオブジェクトが等しい場合、quot;catch" は、(quot;catch" で決定されるように) isEqual: メソッド) を使用すると、同じハッシュ値を持つ必要があります。

イントロスペクション のセクションは Cocoa基礎ガイド をオーバーライドする例があります。 isEqual: という名前のクラスに対して、以下のようにコピーされます。 MyWidget :

- (BOOL)isEqual:(id)other {
    if (other == self)
        return YES;
    if (!other || ![other isKindOfClass:[self class]])
        return NO;
    return [self isEqualToWidget:other];
}

- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
    if (self == aWidget)
        return YES;
    if (![(id)[self name] isEqual:[aWidget name]])
        return NO;
    if (![[self data] isEqualToData:[aWidget data]])
        return NO;
    return YES;
}

ポインタの等質性をチェックし、次にクラスの等質性をチェックし、最後にオブジェクトを isEqualToWidget: をチェックするだけです。 namedata プロパティを使用します。 例題の内容 ではありません。 をオーバーライドする方法です。 hash .

等式に影響しない他のプロパティがあるとします。 age . を使うべきではありません。 hash メソッドをオーバーライドして namedata はハッシュに影響を与えるのでしょうか? もしそうなら、どのようにするのでしょうか?のハッシュを足すだけです。 namedata ? 例えば

- (NSUInteger)hash {
    NSUInteger hash = 0;
    hash += [[self name] hash];
    hash += [[self data] hash];
    return hash;
}

これでいいのでしょうか? もっと良いテクニックはないのでしょうか? もし、プリミティブがあったらどうでしょうか? int ? それらを NSNumber でハッシュを取得できますか? または、以下のような構造体 NSRect ?

( 脳屁 : 元々は "bitwise OR" と一緒に書きました。 |= . 追加という意味)

解決方法は?

まずは

 NSUInteger prime = 31;
 NSUInteger result = 1;

そして、すべてのプリミティブに対して、次のようにします。

 result = prime * result + var

オブジェクトの場合、nil には 0 を、それ以外の場合はハッシュコードを使用します。

 result = prime * result + [var hash];

ブーリアンには、2つの異なる値を使用します。

 result = prime * result + ((var)?1231:1237);


説明と帰属

これはtcurdtさんの作品ではありませんし、コメントでもっと説明を求められたので、帰属のための編集は妥当だと思います。

このアルゴリズムは、書籍 "Effective Java" で一般化されており 該当の章は現在オンラインで見ることができます。 . この本はこのアルゴリズムを普及させ、今では多くのJavaアプリケーション(Eclipseを含む)でデフォルトになっています。 しかし、このアルゴリズムは、Dan BernsteinまたはChris Torekのものとされる、さらに古い実装に由来しています。 この古いアルゴリズムは、もともとUsenetで出回っていたものであり、確実な帰属は困難である。 例えば、いくつかの このApacheのコードには、興味深い解説があります。 (名前を検索してください)で、元のソースを参照しています。

要するに、これは非常に古く、シンプルなハッシュアルゴリズムだということです。 最も高性能というわけではありませんし、数学的に良いアルゴリズムであることが証明されているわけでもありません。 しかし、シンプルであり、多くの人が長い間使って良い結果を出してきたため、歴史的に多くの支持を得ています。