La documentazione per -hash
dice che non deve cambiare mentre un oggetto mutabile è archiviato in una raccolta e allo stesso modo la documentazione per -isEqual:
dice il -hash
il valore deve essere lo stesso per oggetti uguali.
Detto questo, qualcuno ha qualche suggerimento per il modo migliore di implementare -hash
tale da soddisfare entrambe queste condizioni e tuttavia viene effettivamente calcolato in modo intelligente (ovvero non ritorna 0
)? Qualcuno sa come lo fanno le versioni mutabili delle classi fornite dal framework?
La cosa più semplice da fare è ovviamente dimenticarela prima condizione (che non cambia) e assicurati solo di non mutare mai accidentalmente un oggetto mentre si trova in una raccolta, ma mi chiedo se esiste una soluzione più flessibile.
MODIFICARE: Mi chiedo qui se è possibilemantenere i 2 contratti (dove oggetti uguali hanno hash uguali e gli hash non cambiano mentre l'oggetto si trova in una raccolta) quando muto lo stato interno dell'oggetto. La mia inclinazione è dire "no", a meno che non faccia qualcosa di stupido come sempre restituisco 0 per l'hash, ma è per questo che sto facendo questa domanda.
risposte:
2 per risposta № 1Domanda interessante, ma penso a quello che vuoiè logicamente impossibile. Supponiamo che tu inizi con 2 oggetti, A e B. "Sono entrambi diversi e iniziano con codici hash diversi. Aggiungi entrambi a una tabella hash. Ora, vuoi mutare A, ma non puoi cambiare il codice hash perché è già nella tabella. Tuttavia, è possibile cambiare A in modo tale che .equals () B.
In questo caso, hai 2 scelte, nessuna delle quali funziona:
- Cambia l'hashcode di A in uguale a B.hashcode, il che viola il vincolo di non modificare i codici hash mentre sei in una tabella hash.
- Non modificare l'hashcode, nel qual caso A. equals (B) ma non hanno gli stessi hashcode.
Mi sembra che non ci sia modo di farlo senza usare una costante come hashcode.
2 per risposta № 2
La mia lettura della documentazione è che il valore di un oggetto mutabile per hash
può (e probabilmente dovrebbe) cambiare quando è mutato, ma non dovrebbe cambia quando l'oggetto non è stato mutato. La parte della documentazione a cui fare riferimento, quindi, sta dicendo: "Non" mutare oggetti che sono memorizzati in una raccolta, perché ciò causerà il loro hash
valore da cambiare ".
Per citare direttamente dal Documentazione di NSObject per hash
:
Se un oggetto mutabile viene aggiunto a che raccoltausa i valori hash per determinare la posizione dell'oggetto in raccolta, il valore restituito da il metodo hash dell'oggetto non deve cambia mentre l'oggetto è nel collezione. Pertanto, o l'hash il metodo non deve fare affidamentosu uno dei informazioni sullo stato interno dell'oggetto o devi assicurarti che l'oggetto le informazioni sullo stato interno no cambia mentre l'oggetto è nel collezione.
(Enfasi mia.)
1 per risposta № 3
La domanda qui non è come soddisfare entrambi questi requisiti, ma piuttosto quale tu dovrebbero incontrare. Nella documentazione di Apple, si afferma chiaramente che:
un dizionario mutabile può essere inserito in una tabella hash ma non è necessario modificarlo mentre è presente.
Detto questo, sembra più importante che tusoddisfare i requisiti di uguaglianza degli hash. L'hash di un oggetto dovrebbe sempre essere un modo per verificare se un oggetto è uguale a un altro. Se questo non è mai il caso, non è una vera funzione hash.
Solo per finire la mia risposta, fornirò un esempio di una buona implementazione dell'hash. Supponiamo che tu stia scrivendo l'implementazione di -hash
su una raccolta che hai creato. Questa raccolta memorizza una matrice di oggetti NSO come puntatori. Poiché tutti gli oggetti NSO implementano la funzione hash, è possibile utilizzare i loro hash nel calcolo dell'hash della raccolta:
- (NSUInteger)hash {
NSUInteger theHash = 0;
for (NSObject * aPtr in self) { // fast enumeration
theHash ^= [aPtr hash];
}
return theHash;
}
In questo modo, due oggetti di raccolta contenenti gli stessi puntatori (nello stesso ordine) avranno lo stesso hash.
0 per risposta № 4
Dato che stai già eseguendo l'override di -isEqual: per fare un confronto basato sul valore, sei sicuro di aver davvero bisogno di preoccuparti di -hash?
Non riesco a indovinare per cosa hai esattamente bisogno di questoCerto, ma se vuoi fare un confronto basato sul valore senza deviare dalla prevista implementazione di -isEqual: per restituire SÌ solo quando gli hash sono identici, un approccio migliore potrebbe essere quello di imitare NSString "s -isEqualToString :, in modo da creare il tuo -isEqualToFoo: metodo invece di utilizzare o ignorare -isEqual :.
-2 per risposta № 5
In Java, la maggior parte delle classi mutabili non ha la precedenza Object.hashCode () in modo che l'implementazione predefinita restituisca un valore basato sull'indirizzo dell'oggetto e che non cambi. Potrebbe essere lo stesso con l'Obiettivo C.