2010-08-06 15 views
53

In Ruby, qual è la differenza tra == e ===? Il RDoc dice=== vs. == in Ruby

caso Uguaglianza-Per la classe Object, effettivamente la stessa chiamando # ==, ma in genere un limite in discendenti di fornire significativi semantica nella istruzioni case.

È #== uguale a ==? E potresti fornire un esempio di quando/come viene usato nelle dichiarazioni dei casi?

+0

Penso che la migliore risposta qui http://stackoverflow.com/a/4467823/5048945 –

risposta

107

I due in realtà non hanno nulla a che fare con l'altro. In particolare, #== è l'operatore di uguaglianza e #=== non ha assolutamente nulla con l'uguaglianza. Personalmente, trovo piuttosto spiacevole che #=== sembra così simile a #==, usa il segno uguale e viene spesso chiamata la caso uguaglianza, eguali triple operatore o threequals operatore quando non ha davvero nulla a che fare con l'uguaglianza.

Io chiamo #=== il caso di sussunzione operatore (è il migliore che ho potuto inventare, sono aperto a suggerimenti, specialmente da madrelingua inglese).

Il modo migliore per descrivere a === b è "se ho un cassetto con l'etichetta a, ha senso mettere b in esso?"

Quindi, ad esempio, Module#=== verifica se b.is_a?(a). Se hai Integer === 2, ha senso inserire 2 in una casella con etichetta Integer? Sì, lo fa. Che mi dici di Integer === 'hello'? Ovviamente no.

Un altro esempio è Regexp#===. Verifica una partita. Ha senso inserire 'hello' in una casella con etichetta /el+/? Sì, lo fa.

Per le raccolte come catene, Range#=== è definito come un test di appartenenza: ha senso mettere un elemento in una casella con una collezione se tale elemento è nella collezione.

Quindi, questo è ciò che fa #===: verifica se l'argomento può essere riassunto sotto il destinatario.

Cosa deve fare questo con le espressioni case? Semplice:

case foo 
when bar 
    baz 
end 

è lo stesso di

if bar === foo 
    baz 
end 
+4

'Array # ===' non è definito come appartenenza a Ruby 1.8 o 1.9.1. 'Range # ===' è però. – sepp2k

+1

@ sepp2k: hai ragione. Questo è ciò che ottengo assumendo una semantica ragionevole senza prima controllare la documentazione. –

+0

Questo è nuovo per me. Buono a sapersi! – Karl

10

Sì, per #== i documenti indicano "il metodo di istanza == dell'oggetto corrente".

=== viene utilizzato in dichiarazioni caso in quanto tale:

case obj 
when x 
    foo 
when y 
    bar 
end 

è lo stesso di

if x === obj 
    foo 
elsif y === obj 
    bar 
end 

Alcune classi che definiscono la propria === sono Range (di agire come include?), Class (a agire come obj.is_a?(klass)) e Regexp (per agire come =~ eccetto il ritorno di un valore booleano). Alcune classi che non definiscono il proprio === sono le classi numeriche e String.

Così

case x 
when 0 
    puts "Lots" 
when Numeric 
    puts(100.0/x) 
when /^\d+$/ 
    puts(100.0/x.to_f) 
default 
    raise ArgumentError, "x is not a number or numeric string" 
end 

è lo stesso di

if 0 == x 
    puts "Lots" 
elsif x.is_a? Numeric 
    puts(100.0/x) 
elsif x =~ /^\d+$/ 
    puts(100.0/x.to_f) 
else 
    raise ArgumentError, "x is not a number or numeric string" 
end 
+0

Curioso se si dovesse mettere una stringa nell'istruzione when, sarebbe simile a dire 'case x; quando stringa -> se "stringa" == x'? – the12

+1

@ the12 Stai chiedendo se Ruby aggiungerà automaticamente virgolette su un identificatore o che è un refuso? Comunque 'caso x; quando string' è equivalente a 'if string === x', che, se' string' contiene una stringa, equivale a 'if string == x'. Allo stesso modo 'caso x; quando "string" 'è equivalente a' if "string" === x' e 'if" string "== x'. – sepp2k

3

Una curiosità, === viene utilizzata anche per abbinare le eccezioni in rescue

Ecco un esempio

class Example 
    def self.===(exception) 
    puts "Triple equals has been called." 
    true 
    end 
end 

raise rescue Example 
# => prints "Triple equals has been called." 
# => no exception raised 

Questo è usato per abbinare gli errori di sistema.

SystemCallError.=== è stato definito per restituire true quando i due hanno lo stesso errno. Con questo sistema, gli errori di chiamata con lo stesso numero di errore, come Errno::EAGAIN e Errno::EWOULDBLOCK, possono essere recuperati elencando solo uno di essi.