Ruby Language
Operatoren
Suche…
Bemerkungen
Operatoren sind Methoden
Die meisten Operatoren sind eigentlich nur Methoden, also ruft x + y
die +
Methode von x
mit dem Argument y
, das mit x.+(y)
. Wenn Sie eine eigene Methode mit semantischer Bedeutung eines bestimmten Operators schreiben, können Sie Ihre Variante in der Klasse implementieren.
Als dummes Beispiel:
# A class that lets you operate on numbers by name.
class NamedInteger
name_to_value = { 'one' => 1, 'two' => 2, ... }
# define the plus method
def + (left_addend, right_addend)
name_to_value(left_addend) + name_to_value(right_addend)
end
...
end
Wann verwenden Sie &&
vs. and
, ||
gegen or
Beachten Sie, dass es zwei Möglichkeiten gibt, Booleans auszudrücken, entweder &&
oder and
, und ||
oder or
- sie sind oft austauschbar, aber nicht immer. Wir bezeichnen diese als "Zeichen" - und "Wort" -Varianten.
Die Zeichenvarianten haben eine höhere Priorität, sodass weniger Klammern in komplexeren Anweisungen erforderlich sind, um unerwartete Fehler zu vermeiden.
Die Wortvarianten waren ursprünglich als Steuerflussoperatoren und nicht als boolesche Operatoren gedacht. Das heißt, sie wurden für verkettete Methodenanweisungen entwickelt:
raise 'an error' and return
Während sie als Boolesche Operatoren verwendet werden können, deren niedrigere Priorität macht sie unberechenbar.
Zweitens bevorzugen viele Rubyisten die Zeichenvariante, wenn sie einen booleschen Ausdruck erstellen (einen, der als true
oder false
bewertet wird), z. B. x.nil? || x.empty?
. Andererseits werden die Wortvarianten in Fällen bevorzugt, in denen eine Reihe von Methoden ausgewertet wird, und eine kann fehlschlagen. Ein allgemeines Idiom, das die Wortvariante für Methoden verwendet, die im Fehlerfall nil
, könnte beispielsweise so aussehen:
def deliver_email
# If the first fails, try the backup, and if that works, all good
deliver_by_primary or deliver_by_backup and return
# error handling code
end
Bedienerpriorität und Methoden
Vom höchsten zum niedrigsten Wert ist dies die Rangfolge für Ruby. Operationen mit hoher Priorität treten vor Operationen mit niedriger Priorität auf.
╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ Operators ║ Operations ║ Method? ║
╠═══════════════════════╬════════════════════════════════════════╬═════════╣
║ . ║ Method call (e.g. foo.bar) ║ ║
║ [] []= ║ Bracket Lookup, Bracket Set ║ ✓¹ ║
║ ! ~ + ║ Boolean NOT, complement, unary plus ║ ✓² ║
║ ** ║ Exponentiation ║ ✓ ║
║ - ║ Unary minus ║ ✓² ║
║ * / % ║ Multiplication, division, modulo ║ ✓ ║
║ + - ║ Addition, subtraction ║ ✓ ║
║ << >> ║ Bitwise shift ║ ✓ ║
║ & ║ Bitwise AND ║ ✓ ║
║ | ^ ║ Bitwise OR, Bitwise XOR ║ ✓ ║
║ < <= >= > ║ Comparison ║ ✓ ║
║ <=> == != === =~ !~ ║ Equality, pattern matching, comparison ║ ✓³ ║
║ && ║ Boolean AND ║ ║
║ || ║ Boolean OR ║ ║
║ .. ... ║ Inclusive range, Exclusive range ║ ║
║ ? : ║ Ternary operator ║ ║
║ rescue ║ Modifier rescue ║ ║
║ = += -= ║ Assignments ║ ║
║ defined? ║ Defined operator ║ ║
║ not ║ Boolean NOT ║ ║
║ or and ║ Boolean OR, Boolean AND ║ ║
║ if unless while until ║ Modifier if, unless, while, until ║ ║
║ { } ║ Block with braces ║ ║
║ do end ║ Block with do end ║ ║
╚═══════════════════════╩════════════════════════════════════════╩═════════╝
Unary + und Unary - sind für +obj
, -obj
oder -(some_expression)
.
Modifier-if, Modifier-if, usw. sind für die Modifier-Versionen dieser Schlüsselwörter. Dies ist beispielsweise ein Modifikator, sofern kein Ausdruck vorliegt:
a += 1 unless a.zero?
Operatoren mit einem ✓ können als Methoden definiert werden. Die meisten Methoden werden genauso benannt wie der Operator, zum Beispiel:
class Foo
def **(x)
puts "Raising to the power of #{x}"
end
def <<(y)
puts "Shifting left by #{y}"
end
def !
puts "Boolean negation"
end
end
Foo.new ** 2 #=> "Raising to the power of 2"
Foo.new << 3 #=> "Shifting left by 3"
!Foo.new #=> "Boolean negation"
¹ Bei den Bracket-Lookup- und Bracket-Set-Methoden ( []
und []=
) sind ihre Argumente nach dem Namen definiert. Beispiel:
class Foo
def [](x)
puts "Looking up item #{x}"
end
def []=(x,y)
puts "Setting item #{x} to #{y}"
end
end
f = Foo.new
f[:cats] = 42 #=> "Setting item cats to 42"
f[17] #=> "Looking up item 17"
² Die Operatoren "unary plus" und "unary minus" sind beispielsweise als Methoden mit den Namen +@
und -@
definiert
class Foo
def -@
puts "unary minus"
end
def +@
puts "unary plus"
end
end
f = Foo.new
+f #=> "unary plus"
-f #=> "unary minus"
³ In frühen Versionen von Ruby konnten der Ungleichheitsoperator !=
Und der nicht übereinstimmende Operator !~
Nicht als Methoden definiert werden. Stattdessen wurde die Methode für den entsprechenden Gleichheitsoperator ==
oder den Übereinstimmungsoperator =~
aufgerufen, und das Ergebnis dieser Methode wurde von Ruby boolean invertiert.
Wenn Sie keine eigenen !=
Oder !~
Operatoren definieren, ist das oben genannte Verhalten immer noch zutreffend. Ab Ruby 1.9.1 können diese beiden Operatoren jedoch auch als Methoden definiert werden:
class Foo
def ==(x)
puts "checking for EQUALITY with #{x}, returning false"
false
end
end
f = Foo.new
x = (f == 42) #=> "checking for EQUALITY with 42, returning false"
puts x #=> "false"
x = (f != 42) #=> "checking for EQUALITY with 42, returning false"
puts x #=> "true"
class Foo
def !=(x)
puts "Checking for INequality with #{x}"
end
end
f != 42 #=> "checking for INequality with 42"
Operator für Fallgleichheit (===)
Auch als Triple Equals bekannt .
Dieser Operator testet keine Gleichheit, sondern prüft, ob der rechte Operand eine IS-A-Beziehung zum linken Operanden hat. Daher ist der Gleichheitsoperator für gängige Namensfälle irreführend.
Diese SO-Antwort beschreibt es so: Der beste Weg, um a === b
zu beschreiben, ist "wenn ich eine Schublade mit der Bezeichnung a
, ist es sinnvoll, b
in sie zu setzen?" Mit anderen Worten, beinhaltet die Menge a
das Mitglied b
?
Beispiele ( Quelle )
(1..5) === 3 # => true
(1..5) === 6 # => false
Integer === 42 # => true
Integer === 'fourtytwo' # => false
/ell/ === 'Hello' # => true
/ell/ === 'Foobar' # => false
Klassen, die überschreiben ===
Viele Klassen überschreiben ===
, um in Case-Anweisungen eine sinnvolle Semantik bereitzustellen. Einige von ihnen sind:
╔═════════════════╦════════════════════╗
║ Class ║ Synonym for ║
╠═════════════════╬════════════════════╣
║ Array ║ == ║
║ ║ ║
║ Date ║ == ║
║ ║ ║
║ Module ║ is_a? ║
║ ║ ║
║ Object ║ == ║
║ ║ ║
║ Range ║ include? ║
║ ║ ║
║ Regexp ║ =~ ║
║ ║ ║
║ String ║ == ║
╚═════════════════╩════════════════════╝
Empfohlene Praxis
Die explizite Verwendung des Operators für die Gleichheit von Fällen ===
sollte vermieden werden. Es wird keine Gleichheit geprüft, sondern die Subsumtion , und ihre Verwendung kann verwirrend sein. Code ist klarer und verständlicher, wenn stattdessen die Synonymmethode verwendet wird.
# Bad
Integer === 42
(1..5) === 3
/ell/ === 'Hello'
# Good, uses synonym method
42.is_a?(Integer)
(1..5).include?(3)
/ell/ =~ 'Hello'
Sicherer Navigationsbediener
Ruby 2.3.0 fügte den sicheren Navigationsoperator &.
. Dieser Operator soll das Paradigma von object && object.property && object.property.method
in Bedingungsanweisungen verkürzen.
Beispielsweise haben Sie ein House
Objekt mit einer address
, und Sie möchten den street_name
der address
. Um dies sicher zu programmieren, um Null-Fehler in älteren Ruby-Versionen zu vermeiden, verwenden Sie folgenden Code:
if house && house.address && house.address.street_name
house.address.street_name
end
Der sichere Navigationsoperator verkürzt diesen Zustand. Stattdessen können Sie schreiben:
if house&.address&.street_name
house.address.street_name
end
Vorsicht:
Der sichere Navigationsoperator hat nicht genau dasselbe Verhalten wie die verkettete Bedingung. Bei Verwendung der verketteten Bedingung (erstes Beispiel) würde der if
Block nicht ausgeführt, wenn die address
false
. Der sichere Navigationsoperator erkennt nur nil
, lässt jedoch Werte wie " false
. Wenn address
false
, führt die Verwendung des SNO zu einem Fehler:
house&.address&.street_name
# => undefined method `address' for false:FalseClass