2010-03-27 10 views
5

Ecco qualche esempio di codice:Come fa la matrice di Ruby. | confrontare elementi per l'uguaglianza?

class Obj 
    attr :c, true 

    def == that 
    p '==' 
    that.c == self.c 
    end 
    def <=> that 
    p '<=>' 
    that.c <=> self.c 
    end 
    def equal? that 
    p 'equal?' 
    that.c.equal? self.c 
    end 
    def eql? that 
    p 'eql?' 
    that.c.eql? self.c 
    end 
end 

a = Obj.new 
b = Obj.new 

a.c = 1 
b.c = 1 

p [a] | [b] 

esso stampa 2 oggetti ma dovrebbe stampare 1 oggetto. Nessuno dei metodi di confronto viene chiamato. Come è la matrice. | confrontando per l'uguaglianza?

risposta

6

Array#| è implementato utilizzando hashs. Quindi, per fare in modo che il tuo tipo funzioni bene (così come con hashmaps e hashset), dovrai implementare eql? (cosa che hai fatto) e hash (cosa che non hai fatto). Il modo più diretto per definire hash in modo significativo sarebbe quello di restituire c.hash.

+0

Giusto per confermare: il metodo di hash # Array di Ruby garantisce che i valori saranno uguali se e solo se il contenuto degli array è uguale? –

+0

@EricWalker No. È garantito che gli hash di due array sono uguali se (ma non solo se) entrambi gli array contengono elementi con gli stessi valori hash nello stesso ordine. Tuttavia questo non è correlato a questa domanda poiché qui l'hash è chiamato solo sugli elementi, mai sugli array stessi. – sepp2k

1

La classe Array di Ruby è implementata in C, e da quello che posso dire, usa una tabella hash personalizzata per verificare l'uguaglianza quando si confrontano gli oggetti in |. Se si desidera modificare questo comportamento, è necessario scrivere la propria versione che utilizza un controllo di uguaglianza di propria scelta.

Per vedere la piena attuazione di Ruby di Array#|: click here e cercare "rb_ary_or(VALUE ary1, VALUE ary2)"

0

Ruby chiama le funzioni di hash e restituiscono valori diversi, poiché stanno ancora restituendo l'oggetto id predefinito. Avrai bisogno di def hash e restituire qualcosa che riflette la tua idea di ciò che rende un Obj significativo.

>> class Obj2 < Obj 
>> def hash; t = super; p ['hash: ', t]; t; end 
>> end 
=> nil 
>> x, y, x.c, y.c = Obj2.new, Obj2.new, 1, 1 
=> [#<Obj2:0x100302568 @c=1>, #<Obj2:0x100302540 @c=1>, 1, 1] 
>> p [x] | [y] 
["hash: ", 2149061300] 
["hash: ", 2149061280] 
["hash: ", 2149061300] 
["hash: ", 2149061280] 
[#<Obj2:0x100302568 @c=1>, #<Obj2:0x100302540 @c=1>] 
Problemi correlati