=== vs. == in Ruby

70

Was ist in Ruby der Unterschied zwischen == und ===? Das RDoc sagt

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

Ist #==das gleiche wie ==? Und könnten Sie ein Beispiel dafür geben, wann / wie dies in case-Anweisungen verwendet wird?

Mads Mobæk
quelle
Ich denke, die beste Antwort hier stackoverflow.com/a/4467823/5048945
mmike

Antworten:

128

Die beiden haben wirklich nichts miteinander zu tun. Insbesondere #==ist der Gleichheitsoperator und #===hat absolut nichts mit Gleichheit zu tun. Ich persönlich finde es sehr schade , dass #===sieht so ähnlich , #==verwendet das Gleichheitszeichen und oft wird die gerufene Fall Gleichheitsoperator , triple equals Operator oder threequals Operator , wenn es wirklich nichts mit Gleichheit zu tun hat.

Ich rufe #===den Fall-Subsumtions-Operator an (es ist das Beste, was ich mir vorstellen kann, ich bin offen für Vorschläge, insbesondere von englischen Muttersprachlern).

Die beste Art zu beschreiben a === bist: "Wenn ich eine Schublade beschriftet habe a, ist es sinnvoll, sie beinzulegen?"

So wird zum Beispiel Module#===getestet, ob b.is_a?(a). Wenn ja Integer === 2, ist es sinnvoll, 2eine Box mit der Aufschrift zu verwenden Integer? Ja tut es. Was ist mit Integer === 'hello'? Offensichtlich nicht.

Ein anderes Beispiel ist Regexp#===. Es testet auf ein Match. Ist es sinnvoll, 'hello'eine beschriftete Box einzulegen /el+/? Ja tut es.

Für Sammlungen wie Bereiche Range#===wird dies als Mitgliedschaftstest definiert: Es ist sinnvoll, ein Element in ein Feld mit einer Sammlung einzufügen, wenn sich dieses Element in der Sammlung befindet.

Das ist es also, was es #===tut: Es testet, ob das Argument unter dem Empfänger zusammengefasst werden kann.

Was hat das mit caseAusdrücken zu tun? Einfach:

case foo
when bar
  baz
end

ist das gleiche wie

if bar === foo
  baz
end
Jörg W Mittag
quelle
4
Array#===ist nicht als Mitgliedschaft in Ruby 1.8 oder 1.9.1 definiert. Range#===ist aber.
sepp2k
1
@ sepp2k: Du hast recht. Das ist es, was ich bekomme, wenn ich eine vernünftige Semantik annehme, ohne vorher die Dokumentation zu überprüfen.
Jörg W Mittag
10
"Wenn ich eine Schublade mit der Aufschrift a habe, ist es sinnvoll, b hineinzulegen?" Herrliches Bild.
tokland
1
Was ist die Etymologie dieses Operators? Wurde es in Perl oder CLU so verwendet oder etwas Neues von Matz?
Andrew Grimm
1
@ BKSpurgeon: Wirklich? Ich bin nicht einmal Muttersprachler und kenne dieses Wort. Und ich sehe es ziemlich häufig verwendet. Besonders in der Programmierung. Zum Beispiel in dem berühmten Jigsaw-Artikel: "Mixin-basierte Vererbung subsumiert andere Formen der linearen Mehrfachvererbung, die für LISP-basierte objektorientierte Sprachen typisch sind" und aus demselben Artikel "So wie Module und Schnittstellen einige von Linkern unterstützte Funktionen subsumieren, subsumiert die Vererbung einige Funktionen von Texteditoren ".
Jörg W Mittag
11

Ja, mit #==den Dokumenten ist "die Instanzmethode ==des aktuellen Objekts" gemeint .

=== wird in case-Anweisungen als solche verwendet:

case obj
when x
  foo
when y
  bar
end

Ist das gleiche wie

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

Einige Klassen, die ihre eigenen definieren, ===sind Range (um sich so zu verhalten include?), Class (um sich so zu verhalten obj.is_a?(klass)) und Regexp(um sich so zu verhalten, =~außer dass ein Boolescher Wert zurückgegeben wird). Einige Klassen, die keine eigenen definieren, ===sind die numerischen Klassen und String.

Damit

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

ist das gleiche wie

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
sepp2k
quelle
Neugierig, wenn Sie eine Zeichenfolge in die when-Anweisung einfügen würden, wäre es ähnlich zu sagen case x; when string --> if "string" == x?
12.
1
@ the12 Fragen Sie, ob Ruby automatisch Anführungszeichen um einen Bezeichner hinzufügt, oder war das ein Tippfehler? Auf jeden Fall case x; when stringist äquivalent zu if string === x, was, wenn es stringeine Zeichenfolge enthält, äquivalent zu ist if string == x. Ebenso case x; when "string"ist äquivalent zu if "string" === xund if "string" == x.
sepp2k
4

Unterhaltsame Tatsache, ===wird auch verwendet, um Ausnahmen in abzugleichenrescue

Hier ist ein Beispiel

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

Dies wird verwendet, um Systemfehler abzugleichen.

SystemCallError.===wurde so definiert, dass sie true zurückgibt, wenn beide dieselbe errno haben. Mit diesem System können Aufruffehler mit derselben Fehlernummer wie Errno::EAGAINund Errno::EWOULDBLOCKbehoben werden, indem nur einer von ihnen aufgelistet wird.

akuhn
quelle