Was ist der Unterschied zwischen gleich?, Gleichung?, === und ==?

552

Ich versuche den Unterschied zwischen diesen vier Methoden zu verstehen. Ich weiß standardmäßig, dass ==die Methode equal?aufgerufen wird, die true zurückgibt, wenn beide Operanden auf genau dasselbe Objekt verweisen.

===Standardmäßig werden auch ==welche Aufrufe equal?aufgerufen ... okay, wenn also alle drei Methoden nicht überschrieben werden, dann denke ich ===, ==und equal?genau das Gleiche tun?

Jetzt kommt eql?. Was macht das (standardmäßig)? Ruft es den Hash / die ID des Operanden auf?

Warum hat Ruby so viele Gleichheitszeichen? Sollen sie sich in der Semantik unterscheiden?

denniss
quelle
Ich habe gerade angefangen eine irb und hatte folgendes Ergebnis , das Ihre ... Alle diese 3 Widerspruch erfüllt sind: "a" == "a", "a" === "a"und "a".eql? "a". Aber das ist falsch: "a".equal? "a"(Meins ist Rubin 1.9.2-p180)
PeterWong
7
@Peter: Das liegt daran, dass Zeichenfolgen alle Gleichheitsoperatoren überschreiben. Der Versuch , mit a = Object.new; b = Object.newallen dann ==, ===, .equal?, .eql?kehrt truefür avs aund falsch für avs b.
Nemo157

Antworten:

785

Ich werde die Objektdokumentation hier ausführlich zitieren , da ich denke, dass sie einige großartige Erklärungen enthält. Ich empfehle Ihnen, es und auch die Dokumentation für diese Methoden zu lesen, da sie in anderen Klassen wie String überschrieben werden .

Randnotiz: Wenn Sie diese an verschiedenen Objekten selbst ausprobieren möchten, verwenden Sie Folgendes:

class Object
  def all_equals(o)
    ops = [:==, :===, :eql?, :equal?]
    Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
  end
end

"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}

== - generische "Gleichheit"

Gibt auf Objektebene ==nur dann true zurück, wenn objund otherdasselbe Objekt sind. In der Regel wird diese Methode in untergeordneten Klassen überschrieben, um eine klassenspezifische Bedeutung bereitzustellen.

Dies ist der häufigste Vergleich und damit der grundlegendste Ort, an dem Sie (als Autor einer Klasse) entscheiden können, ob zwei Objekte "gleich" sind oder nicht.

=== - Fallgleichheit

Für die Klasse Object entspricht dies praktisch dem Aufruf #==, wird jedoch normalerweise von Nachkommen überschrieben, um in case-Anweisungen eine aussagekräftige Semantik bereitzustellen.

Das ist unglaublich nützlich. Beispiele für Dinge, die interessante ===Implementierungen haben:

  • Angebot
  • Regex
  • Proc (in Ruby 1.9)

So können Sie Dinge tun wie:

case some_object
when /a regex/
  # The regex matches
when 2..4
  # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
  # the lambda returned true
end

In meiner Antwort hier finden Sie ein gutes Beispiel dafür, wie case+ RegexCode viel sauberer machen kann. Und natürlich können Sie durch die Bereitstellung Ihrer eigenen ===Implementierung eine benutzerdefinierte caseSemantik erhalten.

eql?- HashGleichheit

Die eql?Methode liefert true zurück , wenn objund otherauf den gleichen Hash - Schlüssel beziehen. Dies wird verwendet Hash, um Mitglieder auf Gleichheit zu testen. Für Objekte der Klasse Object, eql?ist gleichbedeutend mit ==. Unterklassen setzen diese Tradition normalerweise durch Aliasing eql?auf ihre überschriebene ==Methode fort, es gibt jedoch Ausnahmen. NumericTypen führen beispielsweise eine Typkonvertierung über ==, aber nicht über verschiedene hinweg durch eql?.

1 == 1.0     #=> true
1.eql? 1.0   #=> false

Sie können dies also für Ihre eigenen ==Zwecke überschreiben, oder Sie können es überschreiben und verwenden, alias :eql? :==damit sich die beiden Methoden gleich verhalten.

equal? - Identitätsvergleich

Im Gegensatz dazu ==sollte die equal?Methode niemals von Unterklassen überschrieben werden: Sie wird verwendet, um die Objektidentität zu bestimmen ( a.equal?(b)dh wenn f adasselbe Objekt ist wie b).

Dies ist effektiv ein Zeigervergleich.

jtbandes
quelle
32
Wie ich aus Ihrer Antwort verstehe, lautet die Strenge: gleich? <Äql? <== <===. Normalerweise verwenden Sie ==. Für einige lose Zwecke verwenden Sie ===. Für strenge Situationen verwenden Sie eql? Und für vollständige Identität verwenden Sie gleich?.
Sawa
21
Der Begriff der Strenge wird in der Dokumentation nicht durchgesetzt oder sogar vorgeschlagen, es kommt nur so vor, dass Numericer strenger behandelt wird als ==. Es liegt wirklich am Autor der Klasse. ===wird nur selten außerhalb von caseAnweisungen verwendet.
jtbandes
4
== ist Gleichheit auch in Bezug auf größer / kleiner. Das heißt, wenn Sie Comparable einschließen, wird dies als <=> Rückgabe von 0 definiert. Aus diesem Grund gibt 1 == 1.0 true zurück.
Apeiros
5
@sawa Ich denke normalerweise, dass es ==="Übereinstimmungen" bedeutet (ungefähr). Wie in "Stimmt der reguläre Ausdruck mit der Zeichenfolge überein" oder "Stimmt der Bereich mit der Zahl überein (schließt sie ein)".
Kelvin
7
Unterhaltsame Tatsache: Die offiziellen Dokumente verlinken jetzt auf diese Antwort (siehe ruby-doc.org/core-2.1.5/… ).
Mark Amery
46

Ich liebe jtbandes Antwort, aber da es ziemlich lang ist, werde ich meine eigene kompakte Antwort hinzufügen:

==, ===, eql?,equal?
Sind 4 Komparatoren, dh. 4 Möglichkeiten, 2 Objekte in Ruby zu vergleichen.
Da in Ruby alle Komparatoren (und die meisten Operatoren) tatsächlich Methodenaufrufe sind, können Sie die Semantik dieser Vergleichsmethoden selbst ändern, überschreiben und definieren. Es ist jedoch wichtig zu verstehen, wann Rubys interne Sprachkonstrukte welchen Komparator verwenden:

==(Wertevergleich)
Ruby verwendet: == überall, um die Werte von 2 Objekten zu vergleichen , z. Hash-Werte:

{a: 'z'}  ==  {a: 'Z'}    # => false
{a: 1}    ==  {a: 1.0}    # => true

===(
Fallvergleich ) Ruby verwendet: === in case / when-Konstrukten. Die folgenden Codefragmente sind logisch identisch:

case foo
  when bar;  p 'do something'
end

if bar === foo
  p 'do something'
end

eql?(Hash-Key-Vergleich)
Ruby verwendet: eql? (in Kombination mit dem Methoden-Hash) zum Vergleichen von Hash-Schlüsseln. In den meisten Klassen: Gl. ist identisch mit: ==.
Wissen über: eql? ist nur wichtig, wenn Sie Ihre eigenen speziellen Klassen erstellen möchten:

class Equ
  attr_accessor :val
  alias_method  :initialize, :val=
  def hash()           self.val % 2             end
  def eql?(other)      self.hash == other.hash  end
end

h = {Equ.new(3) => 3,  Equ.new(8) => 8,  Equ.new(15) => 15}    #3 entries, but 2 are :eql?
h.size            # => 2
h[Equ.new(27)]    # => 15

Hinweis: Das häufig verwendete Ruby-Klassen-Set basiert auch auf einem Hash-Schlüssel-Vergleich.

equal?(Objektidentitätsvergleich)
Ruby verwendet: gleich? um zu überprüfen, ob zwei Objekte identisch sind. Diese Methode (der Klasse BasicObject) darf nicht überschrieben werden.

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false
Andreas Rayo Kniep
quelle
30
Es ist eine gute Antwort, aber fast so lang wie die von jtbandes. :)
Odigity
2
@odigity, ungefähr 70% so lang. Ich könnte mir viele Dinge vorstellen, für die ich diese 30% ausgeben könnte.
Cary Swoveland
Ich denke, das Beispiel von eql?ist sehr irreführend. eql?ist ein Gleichheitsvergleich, der mit der Berechnung des Hash übereinstimmt , dh dies a.eql?(b)garantiert a.hash == b.hash. Es werden nicht einfach die Hash-Codes verglichen.
Andrey Tarantsov
Ist der Fallvergleich wirklich gleichwertig bar === foound nicht foo === bar? Ich würde hoffen, dass Letzteres korrekt ist und es wichtig ist, da der Compiler die linke Seite aufruft: === `'
Alexis Wilke
Soweit ich weiß, ist es bar === foo: Ruby verwendet den Fallwert auf der linken Seite und die Fallvariable auf der rechten Seite. Dies hat möglicherweise mit der Vermeidung von NPEs (Null Pointer Exceptions) zu tun.
Andreas Rayo Kniep
34

Gleichheitsoperatoren: == und! =

Der Operator ==, auch als Gleichheit oder Doppelgleichheit bezeichnet, gibt true zurück, wenn beide Objekte gleich sind, und false, wenn dies nicht der Fall ist.

"koan" == "koan" # Output: => true

Der Operator! =, Auch als Ungleichung bekannt, ist das Gegenteil von ==. Es wird true zurückgegeben, wenn beide Objekte nicht gleich sind, und false, wenn sie gleich sind.

"koan" != "discursive thought" # Output: => true

Beachten Sie, dass zwei Arrays mit denselben Elementen in einer anderen Reihenfolge nicht gleich sind, Groß- und Kleinbuchstaben desselben Buchstabens nicht gleich sind und so weiter.

Wenn beim Vergleichen von Zahlen verschiedener Typen (z. B. Integer und Float) der numerische Wert gleich ist, gibt == true zurück.

2 == 2.0 # Output: => true

gleich?

Im Gegensatz zum Operator ==, der prüft, ob beide Operanden gleich sind, prüft die Methode same, ob sich die beiden Operanden auf dasselbe Objekt beziehen. Dies ist die strengste Form der Gleichheit in Ruby.

Beispiel: a = "Zen" b = "Zen"

a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

Im obigen Beispiel haben wir zwei Zeichenfolgen mit demselben Wert. Es handelt sich jedoch um zwei unterschiedliche Objekte mit unterschiedlichen Objekt-IDs. Daher ist das gleiche? Methode gibt false zurück.

Versuchen wir es noch einmal, nur dieses Mal wird b ein Verweis auf a sein. Beachten Sie, dass die Objekt-ID für beide Variablen gleich ist, da sie auf dasselbe Objekt verweisen.

a = "zen"
b = a

a.object_id  # Output: => 18637360
b.object_id  # Output: => 18637360

a.equal? b  # Output: => true

Äql?

In der Hash-Klasse ist die Gl. Methode wird verwendet, um Schlüssel auf Gleichheit zu testen. Einige Hintergrundinformationen sind erforderlich, um dies zu erklären. Im allgemeinen Kontext des Rechnens nimmt eine Hash-Funktion eine Zeichenfolge (oder eine Datei) beliebiger Größe und generiert eine Zeichenfolge oder Ganzzahl fester Größe, die als Hashcode bezeichnet wird und üblicherweise nur als Hash bezeichnet wird. Einige häufig verwendete Hashcode-Typen sind MD5, SHA-1 und CRC. Sie werden in Verschlüsselungsalgorithmen, bei der Datenbankindizierung, bei der Überprüfung der Dateiintegrität usw. verwendet. Einige Programmiersprachen, wie z. B. Ruby, bieten einen Sammlungstyp namens Hash-Tabelle. Hash-Tabellen sind wörterbuchartige Sammlungen, die Daten paarweise speichern und aus eindeutigen Schlüsseln und ihren entsprechenden Werten bestehen. Unter der Haube werden diese Schlüssel als Hashcodes gespeichert. Hash-Tabellen werden üblicherweise nur als Hashes bezeichnet. Beachten Sie, wie sich das Wort Hash auf einen Hashcode oder eine Hash-Tabelle beziehen kann.

Ruby bietet eine integrierte Methode namens Hash zum Generieren von Hashcodes. Im folgenden Beispiel wird eine Zeichenfolge verwendet und ein Hashcode zurückgegeben. Beachten Sie, dass Zeichenfolgen mit demselben Wert immer denselben Hashcode haben, obwohl es sich um unterschiedliche Objekte handelt (mit unterschiedlichen Objekt-IDs).

"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

Die Hash-Methode ist im Kernel-Modul implementiert, das in der Object-Klasse enthalten ist. Dies ist das Standardstammverzeichnis aller Ruby-Objekte. Einige Klassen wie Symbol und Integer verwenden die Standardimplementierung, andere wie String und Hash stellen ihre eigenen Implementierungen bereit.

Symbol.instance_method(:hash).owner  # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel

String.instance_method(:hash).owner  # Output: => String
Hash.instance_method(:hash).owner  # Output: => Hash

Wenn wir in Ruby etwas in einem Hash (einer Sammlung) speichern, wird das als Schlüssel bereitgestellte Objekt (z. B. Zeichenfolge oder Symbol) in einen Hashcode konvertiert und als Hashcode gespeichert. Wenn wir später ein Element aus dem Hash (Sammlung) abrufen, stellen wir ein Objekt als Schlüssel bereit, das in einen Hashcode konvertiert und mit den vorhandenen Schlüsseln verglichen wird. Wenn eine Übereinstimmung vorliegt, wird der Wert des entsprechenden Elements zurückgegeben. Der Vergleich erfolgt mit der Gleichung? Methode unter der Haube.

"zen".eql? "zen"    # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true

In den meisten Fällen ist die Gl. Methode verhält sich ähnlich wie die == Methode. Es gibt jedoch einige Ausnahmen. Zum Beispiel ist Gl. führt keine implizite Typkonvertierung durch, wenn eine Ganzzahl mit einem Float verglichen wird.

2 == 2.0    # Output: => true
2.eql? 2.0    # Output: => false
2.hash == 2.0.hash  # Output: => false

Operator für die Fallgleichheit: ===

Viele der in Ruby integrierten Klassen, wie z. B. String, Range und Regexp, bieten ihre eigenen Implementierungen des Operators ===, auch bekannt als Groß- / Kleinschreibung, Dreifachgleichheit oder Dreifachgleichung. Da es in jeder Klasse unterschiedlich implementiert ist, verhält es sich je nach Objekttyp, für den es aufgerufen wurde, unterschiedlich. Im Allgemeinen wird true zurückgegeben, wenn das Objekt auf der rechten Seite zu dem Objekt auf der linken Seite gehört. Beispielsweise kann damit getestet werden, ob ein Objekt eine Instanz einer Klasse (oder einer ihrer Unterklassen) ist.

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Das gleiche Ergebnis kann mit anderen Methoden erzielt werden, die wahrscheinlich am besten für den Job geeignet sind. Normalerweise ist es besser, Code zu schreiben, der leicht zu lesen ist, indem er so explizit wie möglich ist, ohne die Effizienz und Prägnanz zu beeinträchtigen.

2.is_a? Integer   # Output: => true
2.kind_of? Integer  # Output: => true
2.instance_of? Integer # Output: => false

Beachten Sie, dass das letzte Beispiel false zurückgegeben hat, da Ganzzahlen wie 2 Instanzen der Fixnum-Klasse sind, die eine Unterklasse der Integer-Klasse ist. Das ===, is_a? und instance_of? Methoden geben true zurück, wenn das Objekt eine Instanz der angegebenen Klasse oder einer Unterklasse ist. Die Methode instance_of ist strenger und gibt nur dann true zurück, wenn das Objekt eine Instanz dieser exakten Klasse und keine Unterklasse ist.

Das is_a? und kind_of? Methoden werden im Kernel-Modul implementiert, das von der Object-Klasse gemischt wird. Beide sind Aliase nach derselben Methode. Lassen Sie uns überprüfen:

Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # Ausgabe: => true

Bereichsimplementierung von ===

Wenn der Operator === für ein Bereichsobjekt aufgerufen wird, gibt er true zurück, wenn der Wert rechts in den Bereich links fällt.

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

Denken Sie daran, dass der Operator === die Methode === des linken Objekts aufruft. Also (1..4) === 3 ist äquivalent zu (1..4). === 3. Mit anderen Worten, die Klasse des linken Operanden definiert, welche Implementierung der === Methode sein wird aufgerufen, daher sind die Operandenpositionen nicht austauschbar.

Regexp Implementierung von ===

Gibt true zurück, wenn die Zeichenfolge rechts mit dem regulären Ausdruck links übereinstimmt. / zen / === "Zazen heute üben" # Ausgabe: => true # ist dasselbe wie "Zazen heute üben" = ~ / zen /

Implizite Verwendung des Operators === für case / when-Anweisungen

Dieser Operator wird auch unter der Haube für case / when-Anweisungen verwendet. Das ist die häufigste Verwendung.

minutes = 15

case minutes
  when 10..20
    puts "match"
  else
    puts "no match"
end

# Output: match

Wenn Ruby im obigen Beispiel implizit den doppelten Gleichheitsoperator (==) verwendet hätte, würde der Bereich 10..20 nicht als gleich einer Ganzzahl wie 15 angesehen. Sie stimmen überein, weil der dreifach gleiche Operator (===) ist implizit in allen case / when-Anweisungen verwendet. Der Code im obigen Beispiel entspricht:

if (10..20) === minutes
  puts "match"
else
  puts "no match"
end

Mustervergleichsoperatoren: = ~ und! ~

Die Operatoren = ~ (Equal-Tilde) und! ~ (Bang-Tilde) werden verwendet, um Zeichenfolgen und Symbole mit Regex-Mustern abzugleichen.

Die Implementierung der Methode = ~ in den Klassen String und Symbol erwartet einen regulären Ausdruck (eine Instanz der Regexp-Klasse) als Argument.

"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

:zazen =~ /zen/    # Output: => 2
:zazen =~ /discursive thought/  # Output: => nil

Die Implementierung in der Regexp-Klasse erwartet eine Zeichenfolge oder ein Symbol als Argument.

/zen/ =~ "practice zazen"  # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil

Wenn in allen Implementierungen die Zeichenfolge oder das Symbol mit dem Regexp-Muster übereinstimmt, wird eine Ganzzahl zurückgegeben, die die Position (den Index) der Übereinstimmung darstellt. Wenn keine Übereinstimmung vorliegt, wird null zurückgegeben. Denken Sie daran, dass in Ruby jeder ganzzahlige Wert "wahr" und null "falsch" ist, sodass der Operator = ~ in if-Anweisungen und ternären Operatoren verwendet werden kann.

puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes

Mustervergleichsoperatoren sind auch nützlich, um kürzere if-Anweisungen zu schreiben. Beispiel:

if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
  true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end

Der Operator! ~ Ist das Gegenteil von = ~. Er gibt true zurück, wenn keine Übereinstimmung vorliegt, und false, wenn eine Übereinstimmung vorliegt.

Weitere Informationen finden Sie in diesem Blogbeitrag .

BrunoFacca
quelle
6
Ich finde dies eine bessere Antwort als die derzeit akzeptierte Antwort, da sie schöne Beispiele liefert und weniger zweideutig ist, was die verschiedenen Arten der Gleichheit bedeuten und warum sie existieren / wo sie verwendet werden.
Qqwy
1
Sehr detaillierte Antwort, aber auf meinem irb (Ruby v 2.2.1) :zen === "zen"gibt false zurück
Mike R
@ MikeR Danke, dass du mich informiert hast. Ich habe die Antwort korrigiert.
BrunoFacca
Ich denke du meinst type_of? "Beachten Sie, dass das letzte Beispiel false zurückgegeben hat, da Ganzzahlen wie 2 Instanzen der Fixnum-Klasse sind, die eine Unterklasse der Integer-Klasse ist. Die ===, is_a? Und instance_of? (TYPE_OF?)"?
user1883793
1
Ich liebe diese Antwort. Danke
Abdullah Fadhel
9

Ruby stellt verschiedene Methoden für den Umgang mit Gleichheit vor:

a.equal?(b) # object identity - a and b refer to the same object

a.eql?(b) # object equivalence - a and b have the same value

a == b # object equivalence - a and b have the same value with type conversion.

Lesen Sie weiter, indem Sie auf den unten stehenden Link klicken. Dadurch erhielt ich ein klares, zusammengefasstes Verständnis.

https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

Hoffe es hilft anderen.

Kalibbala
quelle
8

=== # --- Fallgleichheit

== # --- generische Gleichheit

beide funktionieren ähnlich, aber "===" macht sogar case-Anweisungen

"test" == "test"  #=> true
"test" === "test" #=> true

hier der Unterschied

String === "test"   #=> true
String == "test"  #=> false
Kishore Mohan
quelle
3
Sie funktionieren nicht ähnlich, obwohl es in der Regel wahr ist, dass wenn a==bdann a===b. Ist a===baber viel mächtiger. ===ist nicht symmetrisch und a===bbedeutet etwas ganz anderes als b===a, geschweige denn a==b.
mwfearnley
8

Ich möchte den ===Operator erweitern.

=== ist kein Gleichheitsoperator!

Nicht.

Lassen Sie uns diesen Punkt wirklich vermitteln.

Sie kennen sich vielleicht ===als Gleichheitsoperator in Javascript und PHP aus, aber dies ist einfach kein Gleichheitsoperator in Ruby und hat eine grundlegend andere Semantik.

Was macht ===also?

=== ist der Pattern Matching Operator!

  • === stimmt mit regulären Ausdrücken überein
  • === Überprüft die Bereichsmitgliedschaft
  • === prüft, ob es sich um eine Instanz einer Klasse handelt
  • === ruft Lambda-Ausdrücke auf
  • === prüft manchmal die Gleichheit, meistens aber nicht

Wie macht dieser Wahnsinn Sinn?

  • Enumerable#grepverwendet ===intern
  • case whenAnweisungen werden ===intern verwendet
  • Fun Tatsache, rescuenutzt ===intern

Aus diesem Grund können Sie in einer case whenAnweisung reguläre Ausdrücke, Klassen und Bereiche und sogar Lambda-Ausdrücke verwenden .

Einige Beispiele

case value
when /regexp/
  # value matches this regexp
when 4..10
  # value is in range
when MyClass
  # value is an instance of class
when ->(value) { ... }
  # lambda expression returns true
when a, b, c, d
  # value matches one of a through d with `===`
when *array
  # value matches an element in array with `===`
when x
  # values is equal to x unless x is one of the above
end

Alle diese Beispiele funktionieren sowohl mit pattern === valueals auch mit grepMethoden.

arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)                                                                                                                            
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
akuhn
quelle
-8

Ich habe einen einfachen Test für all das geschrieben.

def eq(a, b)
  puts "#{[a, '==',  b]} : #{a == b}"
  puts "#{[a, '===', b]} : #{a === b}"
  puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
  puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end

eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)
Tom Phan
quelle