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


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow