Zoeken…


Opmerkingen

Operators zijn methoden

De meeste operatoren zijn eigenlijk alleen methoden, dus x + y roept de + -methode van x met argument y , dat zou worden geschreven x.+(y) . Als u een eigen methode schrijft met een semantische betekenis van een bepaalde operator, kunt u uw variant in de klas implementeren.

Als een gek voorbeeld:

# 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

Wanneer && vs. and , || vs. or

Merk op dat er twee manieren zijn om Booleans uit te drukken, ofwel && of and , en || of or - ze zijn vaak uitwisselbaar, maar niet altijd. We zullen deze varianten "karakter" en "woord" noemen.

De karaktervarianten hebben een hogere prioriteit, dus het verminderen van de behoefte aan haakjes in complexere beweringen helpt onverwachte fouten te voorkomen.

De woordvarianten waren oorspronkelijk bedoeld als bedieningsstroomoperatoren in plaats van booleaanse operatoren. Dat wil zeggen, ze zijn ontworpen om te worden gebruikt in verklaringen met een kettingmethode:

raise 'an error' and return

Hoewel ze kunnen worden gebruikt als booleaanse operatoren, maakt hun lagere prioriteit ze onvoorspelbaar.

Ten tweede geven veel rubyisten de voorkeur aan de karaktervariant bij het maken van een booleaanse uitdrukking (een die true of false ) zoals x.nil? || x.empty? . Aan de andere kant hebben de woordvarianten de voorkeur in gevallen waarin een reeks methoden wordt geëvalueerd en één kan falen. Een veelvoorkomend idioom dat de woordvariant gebruikt voor methoden die nil bij een fout retourneren, kan er bijvoorbeeld uitzien als:

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

Prioriteit van de operator en methoden

Van hoogste naar laagste, dit is de prioriteitstabel voor Ruby. Operaties met hoge prioriteit vinden plaats vóór operaties met lage prioriteit.

╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ 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 + en unary - zijn voor +obj , -obj of -(some_expression) .

Modifier-if, modifier-tenzij, etc. zijn voor de modificatieversies van die zoekwoorden. Dit is bijvoorbeeld een modifier-tenzij expressie:

a += 1 unless a.zero?

Operators met een ✓ kunnen worden gedefinieerd als methoden. De meeste methoden worden precies zo genoemd als de operator, bijvoorbeeld:

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"

¹ De Bracket-lookup en Bracket Set-methoden ( [] en []= ) hebben hun argumenten gedefinieerd achter de naam, bijvoorbeeld:

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"

² De operatoren "unary plus" en "unary minus" worden gedefinieerd als methoden met de naam +@ en -@ , bijvoorbeeld

class Foo
  def -@
    puts "unary minus"
  end
  def +@
    puts "unary plus"
  end
end

f = Foo.new
+f               #=> "unary plus"
-f               #=> "unary minus"

³ In vroege versies van Ruby konden de operator voor ongelijkheid != En de operator die niet overeenkomt !~ Niet als methoden worden gedefinieerd. In plaats daarvan werd de methode voor de overeenkomstige gelijkheidsoperator == of matching operator =~ aangeroepen, en het resultaat van die methode werd boolean omgekeerd door Ruby.

Als u uw eigen != Of !~ -Operators niet definieert, is het bovenstaande gedrag nog steeds waar. Vanaf Ruby 1.9.1 kunnen deze twee operatoren echter ook als methoden worden gedefinieerd:

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"

Case-gelijkheid operator (===)

Ook bekend als triple is gelijk aan .

Deze operator test geen gelijkheid, maar test eerder of de rechteroperand een IS A-relatie heeft met de linkeroperand. Als zodanig is de populaire operator voor gelijkheid van naamgevallen misleidend.

Dit ZO antwoord beschrijft het als volgt: de beste manier om a === b te beschrijven is "als ik een lade heb met het label a , is het dan logisch om b erin te plaatsen?" Met andere woorden, omvat de set a het lid b ?

Voorbeelden ( bron )

(1..5) === 3            # => true
(1..5) === 6            # => false

Integer === 42          # => true
Integer === 'fourtytwo' # => false

/ell/ === 'Hello'       # => true
/ell/ === 'Foobar'      # => false

Klassen die negeren ===

Veel klassen negeren === om betekenisvolle semantiek te bieden in case-statements. Sommige ervan zijn:

╔═════════════════╦════════════════════╗
║      Class      ║     Synonym for    ║
╠═════════════════╬════════════════════╣
║ Array           ║ ==                 ║
║                 ║                    ║
║ Date            ║ ==                 ║
║                 ║                    ║
║ Module          ║ is_a?              ║
║                 ║                    ║
║ Object          ║ ==                 ║
║                 ║                    ║
║ Range           ║ include?           ║
║                 ║                    ║
║ Regexp          ║ =~                 ║
║                 ║                    ║
║ String          ║ ==                 ║
╚═════════════════╩════════════════════╝

Aanbevolen oefening

Expliciet gebruik van de case-equity-operator === moet worden vermeden. Het test geen gelijkheid maar eerder subsumptie , en het gebruik ervan kan verwarrend zijn. Code is duidelijker en gemakkelijker te begrijpen wanneer in plaats daarvan de synoniemenmethode wordt gebruikt.

# Bad
Integer === 42
(1..5) === 3
/ell/ === 'Hello'

# Good, uses synonym method
42.is_a?(Integer)
(1..5).include?(3)
/ell/ =~ 'Hello'

Veilige navigatie-operator

Ruby 2.3.0 heeft de veilige navigatie-operator toegevoegd , &. . Deze operator is bedoeld om het paradigma van object && object.property && object.property.method in voorwaardelijke verklaringen in te korten.

U hebt bijvoorbeeld een House object met de eigenschap address en u wilt de street_name van het address . Om dit veilig te programmeren om nulfouten in oudere Ruby-versies te voorkomen, gebruikt u code zoiets als dit:

if house && house.address && house.address.street_name
  house.address.street_name
end

De veilige navigatie-operator verkort deze toestand. In plaats daarvan kunt u schrijven:

if house&.address&.street_name
  house.address.street_name
end

Voorzichtigheid:
De veilige navigatie-operator heeft niet precies hetzelfde gedrag als de voorwaardelijke keten. Met behulp van de gekoppelde voorwaardelijke (eerste voorbeeld), zou het if blok niet worden uitgevoerd als, zeg, address false . De veilige navigatie-operator herkent alleen nil , maar staat waarden zoals false . Als het address false , levert het gebruik van SNO een fout op:

house&.address&.street_name
# => undefined method `address' for false:FalseClass


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow